题目传送门
1 /*
2 题意:上司在,员工不在,反之不一定。每一个人有一个权值,问权值和最大多少。
3 树形DP:把上司和员工的关系看成根节点和子节点的关系,两者有状态转移方程:
4 dp[rt][0] += max (dp[son][1], dp[son][0]); //上司不去
5 dp[rt][1] += dp[son][0]; //上司去,员工都不去
6 */
7 #include <cstdio>
8 #include <cstring>
9 #include <algorithm>
10 #include <vector>
11 #include <cmath>
12 using namespace std;
13
14 const int MAXN = 6e3 + 10;
15 const int INF = 0x3f3f3f3f;
16 bool vis[MAXN];
17 vector<int> edge[MAXN];
18 int dp[MAXN][2];
19 int n;
20
21 void DFS(int rt)
22 {
23 vis[rt] = true;
24 dp[rt][0] = 0;
25 for (int i=0; i<edge[rt].size (); ++i)
26 {
27 int son = edge[rt][i];
28 if (!vis[son])
29 {
30 DFS (son);
31 dp[rt][0] += max (dp[son][1], dp[son][0]);
32 dp[rt][1] += dp[son][0];
33 }
34 }
35 }
36
37 int main(void) //URAL 1039 Anniversary Party
38 {
39 // freopen ("URAL_1039.in", "r", stdin);
40
41 while (scanf ("%d", &n) == 1)
42 {
43 memset (vis, false, sizeof (vis));
44 memset (dp, 0, sizeof (dp));
45 for (int i=1; i<=n; ++i) scanf ("%d", &dp[i][1]);
46
47 int l, k;
48 while (scanf ("%d%d", &l, &k) == 2)
49 {
50 if (l == 0 && k == 0) break;
51 vis[l] = true;
52 edge[l].push_back (k);
53 edge[k].push_back (l);
54 }
55
56 int root = 0;
57 for (int i=1; i<=n; ++i)
58 {
59 if (!vis[i]) {root = i; break;}
60 }
61
62 memset (vis, false, sizeof (vis)); DFS (root);
63 printf ("%d
", max (dp[root][0], dp[root][1]));
64 }
65
66 return 0;
67 }