hdu 1011 树形背包

//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 树形背包)