POJ 2486 Apple Tree(树形DP+分组背包)

http://poj.org/problem?id=2486

应该是做的第二道树形DP+背包问题

题意:有颗苹果树n个节点,n-1条边,每个节点上有一定数量的苹果,每经过一条边花费一个单位时间,一共给了T个单位时间

一棵树,从一个节点到另一个节点,如果不是父子关系的话,就要先返回父节点,再到另一个节点;总共给了T个单位时间,最后

不一定再哪个节点,所以还有访问完子节点是否返回根节点的问题,为了表示是否返回,定义状态dp[i][j][0]表示不返回,

dp[i][j][1]表示返回。这题就应该是这两点不好想吧。考虑好这两点,其它的就是考虑好转移过程了,理解好背包问题,不算难。

代码:

//注意的是加边的时候,没说谁是根
#include<iostream>
#include<cstdio>
#include<cstring>
#include<string>
#define nMAX 120
using namespace std;
int num[nMAX],val[nMAX],head[nMAX],s_edge;
int dp[nMAX][nMAX*2][2];
int n,T;
int max(int a,int b)
{
    return a>b?a:b;
}
int min(int a,int b)
{
    return a<b?a:b;
}
struct Edge
{
    int v,nxt;
}edge[nMAX*2];
void addedge(int u,int v)
{
    s_edge++;
    edge[s_edge].v=v;
    edge[s_edge].nxt=head[u];
    head[u]=s_edge;
}
void dfs1(int u,int fa)
{
    num[u]=0;
    for(int e=head[u];e;e=edge[e].nxt)
    {
        int v=edge[e].v;
        if(v==fa) continue;
        dfs1(v,u);
        num[u]+=(num[v]+2);
    }
    num[u]=min(num[u],T);
}
void dfs2(int u,int fa)
{
    int i,j;
    for(int e=head[u];e;e=edge[e].nxt)
    {
        int v=edge[e].v;
        if(v==fa) continue;
        dfs2(v,u);
        for(i=num[u];i>=0;i--)
            for(j=0;j<=num[v];j++)
            {
                //不能返回的
                if(i-j-1>=0)
                {
                    dp[u][i][0]=max(dp[u][i][0],dp[u][i-j-1][1]+dp[v][j][0]);
                    dp[u][i][0]=max(dp[u][i][0],dp[u][i-j-1][1]+dp[v][j][1]);
                }
                if(i-j-2>=0) dp[u][i][0]=max(dp[u][i][0],dp[u][i-j-2][0]+dp[v][j][1]);
                //能返回的
                if(i-j-2>=0)
                  dp[u][i][1]=max(dp[u][i][1],dp[u][i-j-2][1]+dp[v][j][1]);
            }
    }
}
int main()
{
    int i,j,k;
    while(~scanf("%d%d",&n,&T))
    {
        for(i=1;i<=n;i++) scanf("%d",&val[i]);
        memset(head,0,sizeof(head));
        s_edge=0;//开始这里怎么就写成edge++了呢??RE了好几次。。。
        for(i=1;i<n;i++)
        {
            scanf("%d%d",&j,&k);
            addedge(j,k);
            addedge(k,j);
        }
        dfs1(1,-1);//预处理,计算每个点最多花费的时间
        //memset(dp,0,sizeof(dp));
        for(i=1;i<=n;i++)
            for(j=0;j<=T;j++)
            {
                dp[i][j][0]=dp[i][j][1]=0;
            }
        for(i=1;i<=n;i++) dp[i][0][1]=val[i];
        dfs2(1,-1);
        int ans=0;
        for(i=0;i<=num[1];i++)
        {
            ans=max(ans,dp[1][i][0]);
            ans=max(ans,dp[1][i][1]);
        }
        printf("%d\n",ans);
    }
    return 0;
}

  

posted @ 2012-10-20 17:14  快乐.  阅读(265)  评论(0编辑  收藏  举报