Description
有一棵 n 个节点的树,树上每个节点都有一个正整数权值。如果一个点被选择了,那么在树上和它相邻的点都不能被选择。求选出的点的权值和最大是多少?
Input
接下来的一行包含 n 个正整数,第 i 个正整数代表点 i 的权值。
接下来一共 n-1 行,每行描述树上的一条边。
接下来一共 n-1 行,每行描述树上的一条边。
Output
输出一个整数,代表选出的点的权值和的最大值。
Sample Input
5 1 2 3 4 5 1 2 1 3 2 4 2 5
Sample Output
12
HINT
样例说明
选择3、4、5号点,权值和为 3+4+5 = 12 。
数据规模与约定
对于20%的数据, n <= 20。
对于50%的数据, n <= 1000。
对于100%的数据, n <= 100000。
权值均为不超过1000的正整数。
经典树形DP
用dp[i][0]表示不选择i点时,i点及其子树能选出的最大权值,dp[i][1]表示选择i点时,i点及其子树的最大权值。
对于叶子结点:
dp[k][0] = 0;
dp[k][1] = k点权值;
对于非叶子结点:
dp[i][0] =∑max(dp[j][0], dp[j][1]); (j是i的儿子)
dp[i][1] = i点权值 +∑dp[j][0]; (j是i的儿子)
最后树的最大权值即为:max(dp[1][0], dp[1][1])。(要么不包括根结点,要么包括根结点)
1 #include <stdio.h> 2 #include <string.h> 3 #include <iostream> 4 #include <string> 5 #include <math.h> 6 #include <algorithm> 7 #include <vector> 8 #include <stack> 9 #include <queue> 10 #include <set> 11 #include <map> 12 #include <sstream> 13 const int INF=0x3f3f3f3f; 14 typedef long long LL; 15 using namespace std; 16 17 int n; 18 int dp[100005][2]; 19 int vis[100005]; 20 vector<int> vt[100005]; 21 22 void DFS(int st) 23 { 24 vis[st]=1; 25 for(int i=0;i<vt[st].size();i++) 26 { 27 int to=vt[st][i]; 28 if(!vis[to]) 29 { 30 DFS(to); 31 dp[st][1]+=dp[to][0]; 32 dp[st][0]+=max(dp[to][0],dp[to][1]); 33 } 34 } 35 } 36 37 int main() 38 { 39 scanf("%d",&n); 40 for(int i=1;i<=n;i++) 41 scanf("%d",&dp[i][1]); 42 for(int i=1;i<=n-1;i++) 43 { 44 int a,b; 45 scanf("%d %d",&a,&b); 46 vt[a].push_back(b); 47 vt[b].push_back(a); 48 } 49 DFS(1); 50 printf("%d ",max(dp[1][0],dp[1][1])); 51 return 0; 52 }
-