题目分析
题意:有 n 个人去参加派对,如果人 x 去了,那么 x 的直系上司和直属员工都不会去。而且每个人都有一个欢乐值,问如何安排参加派对的人,使得总欢乐值最大,并求出最大欢乐值。
很明显的树形DP,我们用 dp [i] [0] 表示不选取结点 i 的情况下,以 i 为根结点的树的最大值,
dp [i] [1] 表示选取结点 i 的情况下,以 i 为根结点的树的最大值
显然, dp [i] [0] = ∑ { max( dp [ son] [ 0 ] , dp [ son] [ 1] ) } ( son 为 i 的子结点),从子结点中选取最大的值
dp [ i ] [ 1 ] = val [ i ] + ∑ { dp [ son] [ 0 ] } (son 为 i 的子结点),子结点全部不选的情况下的最大值
代码区
#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<vector>
#include<string>
using namespace std;
typedef long long ll;
const int inf = 0x3f3f3f3f;
const int Max = 6e3 + 10;
int val[Max];
vector<int>node[Max];
int dp[Max][2]; // dp[i][0]表示不选结点i的最大值,dp[i][1]表示选择了结点i的最大值
void work(int root,int pre)
{
dp[root][0] = 0;
dp[root][1] = val[root];
for (int i = 0;i < node[root].size();i++)
{
int to = node[root][i];
if (to == pre)
continue;
work(to,root);
dp[root][0] += max(dp[to][0], dp[to][1]); //不选当前结点,那么其最大值来自于子结点选或不选中的最大值
dp[root][1] += dp[to][0]; //选择了当前结点,那么其最大值一定是不选所有子结点的最大值加上自身的值
}
}
int main()
{
std::ios::sync_with_stdio(false);
int n;
while (cin >> n && n)
{
for (int i = 1;i <= n; i++)
{
cin >> val[i];
node[i].clear();
}
for (int i = 1;i < n; i++)
{
int u, v;
cin >> u >> v;
node[u].push_back(v);
node[v].push_back(u);
}
work(1,0);
cout << max(dp[1][0], dp[1][1]) << endl;
}
return 0;
}