The more, The Better HDU

来源:互联网 发布:苏联暴行知乎 编辑:程序博客网 时间:2024/06/13 17:30

传送门

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
中文题,题意就很明白了,很明显的树形dp,其实还是搞不清楚树形dp具体应该怎么写,暂时就是看感觉吧。跟普通的dp一样,首先要找状态转移方程。

dp[i][j]表示当前i节点及其子树下选择j个城市的最大值为dp[i][j]。则状态转移方程为:dp[fa][j] = max(dp[fa][j] , dp[fa][k] + dp[son][j-k]);

借用大佬学弟的话说:树形dp就是dp和dfs的结合,一直无法理解,暂时还是只能写简单的树形dp吧

#include<iostream>#include<stdio.h>#include<string>#include<math.h>#include<queue>#include<vector>#include<string.h>#include<iterator>using namespace std;vector<int>tree[205];int n , m;int dp[205][205] ;void dfs(int fa){    for(int i = 0 ; i < tree[fa].size() ; i ++){        int son = tree[fa][i] ;        if(tree[son].size() > 0)            dfs(son);        for(int j = m ; j > 1 ; j --){            for(int k = 1 ; k < j ; k ++){                dp[fa][j] = max(dp[fa][j] , dp[fa][k] + dp[son][j-k]);            }        }    }}int main(){    while(~scanf("%d%d" , &n , &m)){        if(n == 0 && m == 0)            break;        m++;//m要加1因为要多选择一个0节点        for(int i = 0 ; i <= n ; i ++)            tree[i].clear();        memset(dp , 0 , sizeof(dp));        for(int i = 1 ; i <= n ; i ++){            int sign  , val;            scanf("%d%d" , &sign , &val);            tree[sign].push_back(i);            for(int j = 1 ; j <= m ; j ++){                dp[i][j] = val ;            }        }        dfs(0);        printf("%d\n" , dp[0][m]);    }    return 0;}