【树形DP】HDU 1011 Starship Troopers
通道:http://acm.hdu.edu.cn/showproblem.php?pid=1011
题意:一棵树有n个节点,每个节点有一定的bug值和价值,一个人从1出发有m个兵(1个兵可以打20个bug),经过一个点,要留下足够的兵才能往下走并且获得该点的价值,问如何用m个兵获得最大的价值
思路:dp[i][j]表示在i点放j人能得到的能量,然后背包转移
代码:
#include <stdio.h> #include <string.h> #include <algorithm> using namespace std; int n,m,len; int dp[205][205]; int bug[105],p[105],vis[105],head[205]; struct node { int now,next; } tree[205]; void add(int x,int y) { tree[len].now = y; tree[len].next = head[x]; head[x] = len++; } void dfs(int root) { int cost,i,j,k,son; vis[root] = 1; cost = (bug[root]+19)/20;//不足20的部分也要安排一个 for(i = cost; i<=m; i++) dp[root][i] = p[root];//小于cost的无法获得经验 for(i = head[root]; i!=-1; i = tree[i].next) { son = tree[i].now; if(!vis[son]) { dfs(son); for(j = m; j>=cost; j--) { for(k = 1; j+k<=m; k++) { if(dp[son][k])//到达r的有j+k人,如果留在r有j人,则到达后继节点有k人 dp[root][j+k] = max(dp[root][j+k],dp[root][j]+dp[son][k]); } } } } } int main() { int i,j,x,y; while(~scanf("%d%d",&n,&m),n+m>0) { for(i = 1; i<=n; i++) scanf("%d%d",&bug[i],&p[i]); len = 0; memset(vis,0,sizeof(vis)); memset(head,-1,sizeof(head)); for(i = 1; i<n; i++) { scanf("%d%d",&x,&y); add(x,y); add(y,x); } if(!m) { printf("0\n"); continue; } memset(dp,0,sizeof(dp)); dfs(1); printf("%d\n",dp[1][m]); } return 0; }