树形DP +01背包(HDU 1011)

题意:有n个房间,有n-1条道路连接着n个房间,每个房间都有若干个野怪和一定的能量值,有m个士兵从1房间入口进去,到达每个房间必须要留下若干士兵杀死所有的野怪,然后其他人继续走,(一个士兵可以杀死20只 野怪)问可以获得的最大能量值是多少?

分析:要想进入一个房间,必须把前面所有进过的房间的野怪都杀死,当某个房间的野怪数量是0的时候也需要至少派出一个人来进入这个房间来获得能量。

#include"stdio.h"
#include"string.h"
#include"stdlib.h"
#include"algorithm"
#include"math.h"
#define M 222
#define inf 0x3f3f3f3f
#define eps 1e-10
using namespace std;
struct node
{
    int u,v,next;
}edge[M*2];
int t,head[M],dp[M][M],m,bug[M],value[M],num[M];
void init()
{
    t=0;
    memset(head,-1,sizeof(head));
}
void add(int u,int v)
{
    edge[t].u=u;
    edge[t].v=v;
    edge[t].next=head[u];
    head[u]=t++;
}
void dfs(int u,int f,int cost)
{
    num[u]=(bug[u]+19)/20;
    for(int i=num[u];i<=cost;i++)//当到达当前u节点的时候最多还余下cost士兵
        dp[u][i]=value[u];//把该节点至少需要的士兵到最大的士兵全部赋值
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(v==f)continue;
        dfs(v,u,cost-num[u]);//到达下一间房间还有的士兵数目
        for(int j=cost;j>=num[u];j--)
        {
            for(int k=1;k<=j;k++)
            {
                if(k>=num[v]&&j-k>=num[u])//动态枚举状态搜索最大值
                dp[u][j]=max(dp[u][j],dp[u][j-k]+dp[v][k]);
            }
        }
    }
}
int main()
{
    int n,i,a,b;
    while(scanf("%d%d",&n,&m),n!=-1||m!=-1)
    {
        for(i=1;i<=n;i++)
            scanf("%d%d",&bug[i],&value[i]);
        init();
        for(i=1;i<n;i++)
        {
            scanf("%d%d",&a,&b);
            add(a,b);
            add(b,a);
        }
        memset(dp,0,sizeof(dp));
        if(m==0)
        {
            printf("0\n");
            continue;
        }
        dfs(1,1,m);
        printf("%d\n",dp[1][m]);
    }

}


posted @ 2014-11-14 20:22  一样菜  阅读(327)  评论(0编辑  收藏  举报