题目链接:
https://cn.vjudge.net/problem/URAL-1039
题目大意:
开一个party,每个员工都有一个欢乐值,只有是上司和下属不同时存在时才能欢乐,问怎样安排能有最大的欢乐值。
解题思路:
首先建立上司下属的树形结构,进行树形DP
dp[i][0]表示第i人不参加聚会时,以i为根节点的子树的最大欢乐值
dp[i][1]表示第i人参加聚会时,以i为根节点的子树的最大欢乐值
答案就为max(dp[root][0], dp[root][1])
根据边找到root节点
递推方程:
dp[i][0] = sum(max(dp[son][0], dp[son][1]))第i节点不去,它的儿子可以去,也可以不去
dp[i][1] = a[x] + sum(dp[son][0]) i节点去,那么它的儿子一定不可以去
用dfs来更新dp
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn = 1e4 + 10; 4 vector<int>Map[maxn]; 5 int dp[maxn][2], a[maxn], father[maxn]; 6 void dfs(int x) 7 { 8 dp[x][1] = a[x]; 9 for(int i = 0; i < Map[x].size(); i++) 10 { 11 int son = Map[x][i]; 12 dfs(son); 13 dp[x][0] = max(dp[x][0] + dp[son][1], dp[x][0] + dp[son][0]); 14 dp[x][1] = dp[x][1] + dp[son][0]; 15 } 16 //cout<<x<<dp[x][0]<<dp[x][1]<<endl; 17 } 18 int main() 19 { 20 int n; 21 while(cin >> n) 22 { 23 memset(dp, 0, sizeof(dp)); 24 for(int i = 1; i <= n; i++) 25 { 26 scanf("%d", &a[i]); 27 father[i] = -1; 28 Map[i].clear(); 29 } 30 int u, v; 31 while(scanf("%d%d", &u, &v) != EOF) 32 { 33 if(!u && !v)break; 34 Map[v].push_back(u); 35 father[u] = v; 36 } 37 int root = 1; 38 while(father[root] != -1) 39 { 40 root = father[root]; 41 } 42 dfs(root); 43 cout<<max(dp[root][0], dp[root][1])<<endl; 44 } 45 return 0; 46 }