【树形DP】HDU1561-The more, The Better

来源:互联网 发布:在线编辑源码插件 编辑:程序博客网 时间:2024/05/19 14:39

题目链接:http://acm.split.hdu.edu.cn/showproblem.php?pid=1561

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 20 10 20 37 42 20 10 42 17 17 62 20 0
 

Sample Output
513

代码:

#include<iostream>#include<cstring>#include<vector>#include<queue>#include<cstdio>using namespace std;const int maxn=205;vector<int> edg[maxn];queue<int>  q;int dp[maxn][maxn];       //  dp[rt][k]表示攻克k个城堡所获得的最多宝物数量;int n,m,a;int b[maxn];int vis[maxn];void init(){    for(int i=0;i<maxn;i++)        edg[i].clear();    memset(dp,0,sizeof(dp));    memset(vis,0,sizeof(vis));    while(!q.empty()) q.pop();}void tree_dp(int rt){    vis[rt]=1;    int cnt=edg[rt].size();    for(int i=0;i<cnt;i++){        int son=edg[rt][i];        if(vis[son]==0){            //if(edg[son].size())                tree_dp(son);            //  状态转移方程;            for(int k=m;k>1;k--)   //  枚举容量                for(int l=1;l<k;l++)        //  这里需要注意,k是从1开始,保证根节点取了;                    dp[rt][k]=max(dp[rt][k],(dp[rt][l]+dp[son][k-l]));        }    }}int main(){    while(~scanf("%d%d",&n,&m)){        if(!n&&!m) break;        m+=1;       //  我们添加0为最大根节点,所以可以取得数目要加1;        init();        for(int i=1;i<=n;i++){            scanf("%d%d",&a,&b[i]);            edg[a].push_back(i);            for(int j=1;j<=m;j++)                dp[i][j]=b[i];        }        tree_dp(0);        printf("%d\n",dp[0][m]);    }    return 0;}


0 0