题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=1561
思路:
典型的树形背包题目:
定义dp[i][j]表示以i为根节点,攻打j个城堡的获得的财宝的最优值,那么dp[i][j]=max(dp[i][j],dp[son][k]+dp[i][j-k]) 其中son为i的儿子
然后从叶子节点往上进行背包即可
刚接触的同学会有疑问:就是不知道怎样将题目中的数据建为一个树,其实很简单,只要把0作为根结点即可 0节点的value初始化为0
然后dp[0][m+1]即为求得的答案,是不是很简单啊。。。。
注意初始化。
代码如下:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 #include<iostream> 2 #include<cstdlib> 3 #include<cstdio> 4 #include<cstring> 5 #include<vector> 6 using namespace std; 7 #define MAX 210 8 int dp[MAX][MAX]; 9 vector<int>v[MAX]; 10 int vis[MAX]; 11 int m,n; 12 void init() 13 { 14 memset(dp,-1,sizeof(dp)); 15 memset(vis,0,sizeof(vis)); 16 for(int i=0;i<MAX;i++) v[i].clear(); 17 } 18 void dfs(int root) 19 { 20 vis[root]=1; 21 for(int i=0;i<v[root].size();i++) 22 { 23 if(vis[v[root][i]]) continue; 24 int son=v[root][i]; 25 dfs(son); 26 27 for(int i=m;i>=1;i--) 28 for(int j=0;j<i;j++) 29 if(dp[root][i-j]!=-1&&dp[son][j]!=-1) 30 dp[root][i]=max(dp[root][i],dp[son][j]+dp[root][i-j]); 31 } 32 33 } 34 int main() 35 { 36 while(scanf("%d%d",&n,&m)!=EOF) 37 { 38 init(); 39 if(n==0&&m==0) break; 40 for(int i=1;i<=n;i++) 41 { 42 int a,b; 43 scanf("%d%d",&a,&b); 44 v[a].push_back(i); 45 dp[i][1]=b; 46 dp[i][0]=0; 47 } 48 m++; 49 dp[0][0]=0; 50 dp[0][1]=0; 51 dfs(0); 52 cout<<dp[0][m]<<endl; 53 } 54 return 0; 55 }