http://acm.hdu.edu.cn/showproblem.php?pid=4276

树形dp   比赛时时间不够了没写 

基本思路:

先求是否能到达   如果能到达求每个子树在一定时间下的最优解

ans[i][j] 表示的是 以 i 的父节点为根的子树  还有 j 时间时的最优解

注意的是 到n的路径必须走无需返回 其他的可以走且需要返回

还有一条路所花时间可能是 0 (这里让我wa了N久呀)

代码及其注释:

 

#include <iostream>
#include <cstdio>
#include <cstring>
#include <map>
#include <vector>
#include <algorithm>

#define LL long long

using namespace std;

const int N=103;
const int INF=0x5fffffff;
int a[N];//财宝
int ans[N][N*5];//如上所诉
//邻接表
int head[N];
struct node
{
    int j,next;
    int d;
}side[N*2];
int I;
int n;
int limit[N];//为-1 表示没有限制  否则表示是到出口的路径 必须走 而且到 i 的时候时间最少为limit[i]
void build(int i,int j,int d)
{
    side[I].j=j;
    side[I].d=d;
    side[I].next=head[i];
    head[i]=I++;
}
void dfs(int x,int pre)//求出limit 并且去掉多余边
{
    int f=0;
    for(int t=head[x];t!=0;f=t,t=side[t].next)
    {
        int l=side[t].j;
        if(l!=pre)
        {
            dfs(l,x);
            if(limit[l]!=-1)
            limit[x]=limit[l]+side[t].d;
        }else
        {
            if(f==0)
            head[x]=side[t].next;
            else
            side[f].next=side[t].next;
        }
    }
    if(x==n)
    limit[x]=0;
}
int dp(int x,int m)
{
    int l=side[x].j;
    if(ans[l][m]!=-1)//表
    return ans[l][m];
    if(limit[l]!=-1&&side[x].d+limit[l]>m)//此路必走 但时间不够则属于非法的走法 答案负无穷
    {
        ans[l][m]=-INF;return ans[l][m];
    }
    ans[l][m]=0;
    if(l==0)//没有节点
    {return ans[l][m];}
    if(limit[l]==-1)//可以直接到兄弟节点 此节点不走
    ans[l][m]=dp(side[x].next,m);
    if(limit[l]==-1)
    {
        int temp=m-side[x].d*2;//往返
        for(int i=0;i<=temp;++i)
        {
            ans[l][m]=max(ans[l][m],a[l]+dp(head[l],i)+dp(side[x].next,temp-i));
        }
    }else
    {
        int temp=m-side[x].d;//无需往返 时间至少为limit[l]
        for(int i=limit[l];i<=temp;++i)
        {
            ans[l][m]=max(ans[l][m],a[l]+dp(head[l],i)+dp(side[x].next,temp-i));
        }
    }
    return ans[l][m];
}
int main()
{
    //freopen("data.txt","r",stdin);
    int m;
    while(scanf("%d %d",&n,&m)!=EOF)
    {
        memset(head,0,sizeof(head));
        side[0].j=0;
        I=1;
        for(int i=1;i<n;++i)
        {
            int l,r,d;
            scanf("%d %d %d",&l,&r,&d);
            build(l,r,d);
            build(r,l,d);
        }
        for(int i=1;i<=n;++i)
        scanf("%d",&a[i]);
        memset(limit,-1,sizeof(limit));
        dfs(1,-1);
        if(limit[1]>m)
        {
            printf("Human beings die in pursuit of wealth, and birds die in pursuit of food!\n");
            continue;
        }
        memset(ans,-1,sizeof(ans));
        printf("%d\n", a[1]+dp(head[1],m));//第一个节点无需时间
    }
    return 0;
}

 

posted on 2012-09-11 19:52  夜->  阅读(227)  评论(0编辑  收藏  举报