//7506735 2013-01-17 17:24:53 Accepted 1011 93MS 272K 1450 B G++ chen
//第一道树形dp,转移方程为dp[i][j]=max(dp[i][j],dp[i][j-k]+dp[son[i]][k]),这里的k指的是父亲节点分给孩子节点的士兵个数
//这其实是保证父节点有足够士兵的前提下,对孩子节点进行的01背包,max中第一个式子表示孩子节点不放,第二个节点表示放孩子节点
//注意这一题有特殊情况,也就是说即使某个洞没有bug,但是为了获得brain还是需要士兵去,但是士兵可以不停留
//5 0
//0 1 0 1 0 5 0 1 0 2 1 2 1 3 2 4 2 5 需要特判0的情况
//5 2
//0 1 0 1 0 5 0 1 0 2 1 2 1 3 2 4 2 5
//答案分别是 0,9
#include<stdio.h>
#include<stdlib.h>
#include<vector>
#include<algorithm>
#define maxn 105
using namespace std;
int dp[maxn][maxn];
int c[maxn];
int w[maxn];
int n,m;
vector<int> child[maxn];
//由于图是双向连通的,所以必须设置这一项
int vis[maxn];
void dfs(int x){
vis[x]=1;
for(int i=c[x];i<=m;i++)
dp[x][i]=w[x];
//对于每个孩子节点
for(int i=0;i<child[x].size();i++){
int son=child[x][i];
if(vis[son]) continue;//如果已经访问过了,继续遍历下一节点
dfs(son);
for(int v=m;v>=c[x];v--){
for(int k=1;k+c[x]<=v;k++)
dp[x][v]=max(dp[x][v],dp[x][v-k]+dp[son][k]);
}
}
}
int main(){
while(scanf("%d%d",&n,&m)!=EOF){
if(n==-1&&m==-1)
break;
//初始化
for(int i=1;i<=n;i++)
if(!child[i].empty())
child[i].clear();
for(int i=1;i<=n;i++){
scanf("%d%d",&c[i],&w[i]);
c[i]=(c[i]%20==0?c[i]/20:c[i]/20+1);
}
int a,b;
for(int i=0;i<n-1;i++){
scanf("%d%d",&a,&b);
child[a].push_back(b);
child[b].push_back(a);
}
//dfs
memset(dp,0,sizeof(dp));
memset(vis,0,sizeof(vis));
dfs(1);
if(m==0)
printf("0\n");
else
printf("%d\n",dp[1][m]);
}
//system("pause");
return 0;
}
hdu 1011 树形背包
最新推荐文章于 2013-04-18 17:24:47 发布