问题描述
有一棵 n 个节点的树,树上每个节点都有一个正整数权值。如果一个点被选择了,那么在树上和它相邻的点都不能被选择。求选出的点的权值和最大是多少?
输入格式
第一行包含一个整数 n 。
接下来的一行包含 n 个正整数,第 i 个正整数代表点 i 的权值。
接下来一共 n-1 行,每行描述树上的一条边。
输出格式
输出一个整数,代表选出的点的权值和的最大值。
样例输入
5
1 2 3 4 5
1 2
1 3
2 4
2 5
样例输出
12
样例说明
选择3、4、5号点,权值和为 3+4+5 = 12 。
数据规模与约定
对于20%的数据, n <= 20。
对于50%的数据, n <= 1000。
对于100%的数据, n <= 100000。
权值均为不超过1000的正整数。
代码:(详细解析见注释)
1. ///邻接表构建过程
2. #include <iostream>
3. #include <cstdio>
4. #include <cstring>
5. #include <algorithm>
6. #include <vector>
7. using namespace std;
8. typedef long long LL;
9.
10. struct Edge{
11. int edge;
12. int next;
13. }e[300000];
14.
15. int head[300000],val[300000];
16. int N,M;
17. LL dp[150000][2]; ///dp[s/u][0/1],u为s的子节点,0表示包含自己的以s为根节点的子树最大值,1表示不包含自己的以s为根节点的子树最大值
18. bool v[150000];
19.
20. void add(int s,int ee)
21. {
22. e[++M].edge = ee; ///边的终点
23. e[M].next = head[s]; ///邻边
24. head[s] = M; ///当前边
25. }
26.
27. void dfs(int s)
28. {
29. dp[s][0]=val[s];
30. dp[s][1]=0;
31. for(int i=head[s];i!=-1;i=e[i].next)
32. {
33. int u=e[i].edge;
34. if(v[u]==0)
35. {
36. v[u]=1;
37. dfs(u);
38. dp[s][0]+=dp[u][1];
39. dp[s][1]+=max(dp[u][1],dp[u][0]);
40. v[u]=0;
41. }
42. }
43.
44. }
45.
46. int main()
47. {
48. int s,e;
49. int ans=0;
50. memset(head,-1,sizeof(head));
51. memset(dp,0,sizeof(dp));
52. memset(v,0,sizeof(v));
53. cin>>N;
54. for(int i=1;i<=N;i++)
55. cin>>val[i];
56. for(int i=1;i<N;i++)
57. {
58. cin>>s>>e;
59. add(s,e);
60. add(e,s);
61. }
62. v[1]=1;
63. dfs(1);
64. v[1]=0;
65. ans=max(dp[1][0],dp[1][1]);
66. cout<<ans<<endl;
67. return 0;
68. }