hdu1561The more, The Better(树形背包)

Posted HWIM

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hdu1561The more, The Better(树形背包)相关的知识,希望对你有一定的参考价值。

The more, The Better

Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 8811    Accepted Submission(s): 5141


Problem Description

ACboy很喜欢玩一种战略游戏,在一个地图上,有N座城堡,每座城堡都有一定的宝物,在每次游戏中ACboy允许攻克M个城堡并获得里面的宝物。但由于地理位置原因,有些城堡不能直接攻克,要攻克这些城堡必须先攻克其他某一个特定的城堡。你能帮ACboy算出要获得尽量多的宝物应该攻克哪M个城堡吗?
 

 

Input

每个测试实例首先包括2个整数,N,M.(1 <= M <= N <= 200);在接下来的N行里,每行包括2个整数,a,b. 在第 i 行,a 代表要攻克第 i 个城堡必须先攻克第 a 个城堡,如果 a = 0 则代表可以直接攻克第 i 个城堡。b 代表第 i 个城堡的宝物数量, b >= 0。当N = 0, M = 0输入结束。
 

 

Output

对于每个测试实例,输出一个整数,代表ACboy攻克M个城堡所获得的最多宝物的数量。
 

 

Sample Input

3 2 0 1 0 2 0 3 7 4 2 2 0 1 0 4 2 1 7 1 7 6 2 2 0 0
 

 

Sample Output

5 13
 

 

code

第一道树形背包题!

写的题解很啰嗦,是我第一次的时有的疑问。

 1 /*
 2 hdu 1561 : The more,the better 
 3 
 4 dp[i][j] : 当前i节点及其子树下选择j个城市的最大值为dp[i][j];
 5 
 6 这一道题目注意建立了一个超级根节点0,
 7 任何点都要先拿0才可以。所以后面很多地方都是m+1 
 8 
 9 下面的转移方程中有一句dp[u][j] = max(dp[u][j],dp[u][j-k]+dp[v][k]);
10 那么可能就有疑问了:dp[u][j-k]+dp[v][k] 
11 从子树v中取出k个点 与  根树u中取出的j-k个点 合并成 从根树中取j个点
12 仔细读完就会发现问题了:既然v是u的子树,那么dp[v][k]会不会和dp[u][j-k]冲突呢
13 即:从子树v中取出K个点,然后在u中取出j-k个点,会不会v中的点又在u个点中出现了呢
14 答案是不会的。
15 因为遍历每个从u遍历v,递归求解出dp[v]的值,用v来更新u,也就是说在以前是没有便利到v
16 的,所以dp[u]中也不是由v更新的,所以dp[u][j-k]的点没有子树v中的点 
17 
18 然后注意转移时m一定要逆序,和01背包相似
19 01:背包加入一个物品,然后用这个物品更新
20 f[v],f[v]=max(f[v],f[v-Tiji[i]]+jiazhi[i])
21 树上的相似:加入一个物品,即遍历到v,然后用这个物品更新
22 dp[v] = max(dp[v],dp[v-k]+(新节点)子树大小为k的最大价值) //后面的那个递归求解。 
23 然后由于树形背包的限制(拿v之前先拿u)加了一维。 
24 
25 
26 */
27 
28 #include<cstdio>
29 #include<algorithm>
30 #include<cstring>
31 
32 using namespace std;
33 
34 const int MAXN = 210;
35 const int MAXM = 50010;
36 
37 struct Edge{
38     int to,nxt;
39 }e[MAXM];
40 int head[MAXM],tot;
41 int val[MAXN],dp[MAXN][MAXN];
42 
43 inline int read() {
44     int x = 0,f = 1;char ch = getchar();
45     for (; ch<0||ch>9; ch = getchar())
46         if (ch==-) f = -1;
47     for (; ch>=0&&ch<=9; ch = getchar())
48         x = x*10+ch-0;
49     return x*f;
50 }
51 inline void add_edge(int u,int v) {
52     e[++tot].to = v,e[tot].nxt = head[u],head[u] = tot;
53 }
54 inline void init() {
55     memset(head,0,sizeof(head));
56     memset(dp,0,sizeof(dp));
57     tot = 0;
58 }
59 void dfs(int u,int m) {
60     dp[u][1] = val[u];
61     for (int i=head[u]; i; i=e[i].nxt) {
62         int v = e[i].to;
63         dfs(v,m);
64         for (int j=m; j>=2; --j) 
65             for (int k=0; k<j; ++k) 
66                 dp[u][j] = max(dp[u][j],dp[u][j-k]+dp[v][k]);
67     }
68 }
69 int main() { 
70     int n,m;
71     while (scanf("%d%d",&n,&m)!=EOF && n+m!=0) {
72         init();
73         for (int u,v,i=1; i<=n; ++i) {
74             u = read(),v = read();
75             val[i] = v;
76             add_edge(u,i);
77         }
78         val[0] = 0; // 超级根节点权值为0 
79         dfs(0,m+1); // 从0开始 
80         printf("%d\n",dp[0][m+1]);
81     }    
82     return 0;
83 }

 

 
 

以上是关于hdu1561The more, The Better(树形背包)的主要内容,如果未能解决你的问题,请参考以下文章

hdu 1561 The more, The Better(树形dp)

hdu1561The more, The Better(树形背包)

hdu1561 The more, The Better (树形DP)

hdu 1561 The more, The Better 树形dp

HDU1561 The more, The Better(树型DP)

hdu 1561 The more, The Better (依赖背包 树形dp)