hdu 1561树形dp+分组背包

/*
HDU  1561 The more, The Better
树形DP + 分组背包
建立一颗数,选了子节点,必选父亲结点。
对于每个结点,它的子结点就是个分组背包
*/
#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<iostream>
using namespace std;
const int MAXN=220;
struct Node
{
    int to;
    int next;
};
Node edge[MAXN];//建立的有向数,和结点数一样就可以了
int tol;
int head[MAXN];//头结点
int value[MAXN];//每个结点的宝物数量

int dp[MAXN][MAXN];//dp[i][j]表示在以i为根的子树上,攻克j个结点获得的最大价值

void init()
{
    memset(head,-1,sizeof(head));
    tol=0;
    memset(dp,0,sizeof(dp));
}

void add_edge(int a,int b) //建立一条a->b的有向边
{
    edge[tol].to=b;
    edge[tol].next=head[a];
    head[a]=tol++;
}

int n,m;

void dfs(int u)
{
    dp[u][1]=value[u];//选一个肯定选自己这个结点
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].to;
        dfs(v);
        //分组背包,外层是对所有的组(参考背包九讲)
        for(int k=m;k>=1;k--)  //for v <- V to 0
        //下面这个循环必须是j<k结束,不能取等号,因为至少需要留一个点来取u点
          for(int j=1;j<k;j++) // do for 所有的属于当前组
            dp[u][k]=max(dp[u][k],dp[u][k-j]+dp[v][j]);
    }
}

int main()
{
    int a,b;
    while(scanf("%d%d",&n,&m)!=EOF)
    {
        if(n==0&&m==0)break;
        init();
        for(int i=1;i<=n;i++)
        {
            scanf("%d%d",&a,&b);
            value[i]=b;
            add_edge(a,i);
        }
        value[0]=0;
        m++;//虚拟构造了结点0
        dfs(0);

        printf("%d\n",dp[0][m]);
    }
    return 0;
}

你可能感兴趣的:(hdu 1561树形dp+分组背包)