【树形DP】P1352 没有上司的舞会

本文探讨了一道典型的树形DP题目——没有上司的舞会,通过分析题目背景,将其转化为树上相邻节点不可同时选取的问题,进而求解所取节点之和的最大值。文章详细解释了状态转移方程,并提供了完整的代码实现。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

【树形DP】P1352 没有上司的舞会

题目传送门

分析:

题目里明确告诉了你上司与下属的关系是一颗树,所以这一题是很明显的树形DP,而因为下属和直接上司不能同时参加,所以问题转换成一棵树上相邻的节点不能同时取,求所取点和的最大值。

那么我们可以自上而下地思考,对于一个节点,自身有取或不取两种情况,对应这两种情况的子树情况也不一样,可以分类讨论:

  1. 如果这个节点自身取,则他的直接儿子都不能取
  2. 如果这个节点自身不取,则他的儿子可以取,也可以不取(我一开始接触的时候总是写成一定要取)

那么我们如果用f[x][0]表示x节点不取,f[x][1]表示节点x取,那么状态转移方程可以写出

f[x][0]=\sum (f[i][0]+f[i][1])其中i是x的直接儿子

f[x][1]=\sum (f[i][0])+a[x]其中i同上,a[i]是第i个人的幽默值。

代码

当然,有根树还要先找到根,然后进行dfs

#include <bits/stdc++.h>
#define MAX 6005
using namespace std;

int n, a[MAX], f[MAX][2];
vector<int> t[MAX];

int dfs(int x, int op){        //op==0不选, op==1选
    if(f[x][op] > 0){
        return f[x][op];
    }
    if(t[x].size() == 0){
        if(!op) {
            f[x][op] = 0;
            return 0;
        }
        else {
            f[x][op] = a[x];
            return a[x];
        }
    }
    int s1 = a[x], s2 = 0;
    for (int i = 0; i < t[x].size(); ++i) {
        s1 += dfs(t[x][i], 0);
    }
    for (int i = 0; i < t[x].size(); ++i) {
        s2 += max(dfs(t[x][i], 0), dfs(t[x][i], 1));
    }
    f[x][0] = s2;
    f[x][1] = s1;
    return f[x][op];
}

int main()
{
    cin >> n;
    for (int i = 1; i <= n; ++i) {
        scanf("%d", &a[i]);
    }
    int l , k, root, vis[MAX] = {false};
    for (int i = 1; i < n; ++i) {
        scanf("%d %d", &l, &k);
        vis[l] = true;
        t[k].push_back(l);
    }
    for (int i = 1; i <= n; ++i) {
        if(!vis[i]){
            root = i;
            break;
        }
    }
    int ans = max(dfs(root, 1), dfs(root, 0));
    cout << ans << endl;

    return 0;
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值