结点选择(树形DP)

Description

有一棵 n 个节点的树,树上每个节点都有一个正整数权值。如果一个点被选择了,那么在树上和它相邻的点都不能被选择。求选出的点的权值和最大是多少?

Input

接下来的一行包含 n 个正整数,第 i 个正整数代表点 i 的权值。
接下来一共 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 }

-

原文地址:https://www.cnblogs.com/jiamian/p/12194258.html