The more, The Better
Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 9169 Accepted Submission(s): 5343
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
Author
8600
注意到宝物之间的关系可以用一颗有向树来表示,0号节点就是根,用f[i][j]表示由i号节点延伸j个节点(包括i在内)可以达到的最大价值,对于当前节点,对他的每一个儿子跑一遍背包,枚举当前儿子包含的节点数k,那么之前所有儿子包含的节点数就是j-k(算上父亲),最后答案就是f[0][m+1];
注意节点数j要降序枚举否则更新后的数组会影响后面的状态。
1 #include<bits/stdc++.h> 2 using namespace std; 3 #define inf 0x3f3f3f3f 4 int first[220],tot; 5 int f[210][210]; 6 struct Edge 7 { 8 int v,next; 9 }e[500]; 10 void add(int u,int v) 11 { 12 e[tot].v=v; 13 e[tot].next=first[u]; 14 first[u]=tot++; 15 } 16 int b[220],M,N; 17 int dfs(int u) 18 { 19 f[u][1]=b[u]; 20 int s=1; 21 for(int i=first[u];~i;i=e[i].next){ 22 int v=e[i].v; 23 int son=dfs(v); 24 s+=son; 25 for(int j=M+1;j>=1;--j){ 26 for(int k=1;j-1>=k&&k<=son;++k){ 27 f[u][j]=max(f[u][j],f[u][j-k]+f[v][k]); 28 } 29 } 30 } 31 return s; 32 } 33 int main() 34 { 35 int n,m,i,j,k; 36 while(cin>>n>>m&&(n||m)){ 37 N=n,M=m; 38 memset(f,0,sizeof(f)); 39 memset(first,-1,sizeof(first)); 40 tot=0; 41 for(i=1;i<=n;++i){ 42 scanf("%d%d",&k,&b[i]); 43 add(k,i); 44 } 45 dfs(0); 46 //cout<<f[1][1]<<' '<<f[2][1]<<' '<<f[3][1]<<endl; 47 cout<<f[0][m+1]<<endl; 48 } 49 return 0; 50 }