CDOJ 1136 树形01背包

来源:互联网 发布:ubuntu 14.04 下载 编辑:程序博客网 时间:2024/06/15 20:10

dp[u][i]表示在以u为根节点的子树上,选i个物品的最大价值。
然后转移方程就是dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]),就是他可以从当前已更新的部分选j-k个,然后在要更新的那个儿子节点那里选k个,v是当前更新到的子节点,这样把k从1到j-1扫一遍,就把这个子节点更新了。

#include<bits/stdc++.h>using namespace std;const int maxn=205;const int maxm=205;struct node{    int to,next;}E[maxm];int head[maxn],tot;int n,m;int v[maxn],dp[maxn][maxn];void add(int u,int v){    E[tot].to=v;    E[tot].next=head[u];    head[u]=tot++;}void init(){    memset(head,-1,sizeof(head));    tot=0;    memset(E,0,sizeof(E));    memset(dp,0,sizeof(dp));}void dfs(int x){    dp[x][1]=v[x];    for(int i=head[x];i!=-1;i=E[i].next){        int to=E[i].to;        dfs(to);        for(int j=m;j>=0;j--){            for(int k=0;k<j;k++){                dp[x][j]=max(dp[x][j],dp[x][j-k]+dp[to][k]);            }        }    }}int main(){    while(~scanf("%d%d",&n,&m)){        if(n==0&&m==0)break;        m++;        init();        int a;        for(int i=1;i<=n;i++){            scanf("%d%d",&a,&v[i]);            add(a,i);        }        dfs(0);        printf("%d\n",dp[0][m]);    }    return 0;}
0 0