没有上司的舞会
树形dp的基础题。
由于是一个树形结构,所以我们和容易就可以得到一个拓扑图,由此我们在存图时只需要存下每个点的入度,然后对入度为0的节点进行搜索dp即可。
状态表示为f[i][2],f[i][0]表示第i个人不参加宴会的最大快乐指数,f[i][1]表示第i个人参加宴会的快乐指数,所以我们的状态转移方程为:
1 f[i][1] = max(w[i], f[j1][0] + f[j2][0] + ..... + f[jn][0]); // 当第i个人参加宴会时他的下属都不能参加宴会,所以需要求得每个下属不参加宴会时的快乐值的和。 2 f[i][0] = max(f[j1][1], f[j1][0]) + max(f[j2][1], f[j2][0]) + ..... + max(f[jn][0], f[n1][1]); // 当第i个人不参加宴会时他的下属可以参加也可以不参加,所以就是max(f[j1....jn][0], f[j1....jn][1])。
代码:
1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 #include <algorithm> 5 #include <cmath> 6 7 using namespace std; 8 9 typedef long long LL; 10 11 const int N = 6010; 12 13 int n, m; 14 int w[N], h[N], ne[N], e[N], idx; 15 int f[N][2]; 16 int in[N]; 17 18 void add(int a, int b) 19 { 20 e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ; 21 } 22 23 void dfs(int u) 24 { 25 int res = 0; 26 for (int i = h[u]; i != -1; i = ne[i]) 27 { 28 int j = e[i]; 29 dfs(j); 30 f[u][0] += max(f[j][0], f[j][1]); 31 res = max(res, res + f[j][0]); 32 } 33 34 f[u][1] = max(w[u], w[u] + res); 35 } 36 37 int main() 38 { 39 cin >> n; 40 memset(h, -1, sizeof h); 41 for (int i = 1; i <= n; i ++ ) cin >> w[i]; 42 for (int i = 1; i <= n - 1; i ++ ) 43 { 44 int a, b; 45 cin >> a >> b; 46 add(b, a); 47 in[a] ++ ; 48 } 49 50 int t = 0; 51 for (int i = 1; i <= n; i ++ ) 52 if (!in[i]) 53 { 54 t = i; 55 break; 56 } 57 58 dfs(t); 59 60 cout << max(f[t][1], f[t][0]) << endl; 61 62 return 0; 63 }