hdu 4276 The Ghost Blows Light(Spfa+树形dp)

题意:

一个盗墓者去盗墓,结果墓要倒塌了,现在他有T的时间从入口1到达出口n,每天路有需要一定时间才能走完,由于是去盗墓所以要多拿点财宝,每个点都有一定数量的财宝,于是问你这个人能不能到出去,如果能输出最多能拿多少财宝。

题解:
我们可以这样分析,对于这样的情况我们首先要保证一定能到达出口,那么先让最短路求出能到达出口的最短时间,那么现在分析第二点,如何拿到最大价值的财宝,那么我们可以这样想,你现在知道了最短路的路径了,那么是我的话肯定首先走最短路径这条路,那么在有时间剩余的前提下我们选择从最短路的一个点跑到其他点拿点财宝在回来,这样肯定能保证最优?

为什么呢?如果这个目的的地图是一个图(不是树)那么就有可能出现这种情况:从最短路的一个点去另外的一个,那么从另外一个点在出发就有可能找到比之前更优的路。但是这题是树,因为树没有多个点连到一个点,那么这种情况就不存在,于是我们就很大胆的得出之前那个结论。

#include<iostream>
#include<math.h>
#include<stdio.h>
#include<algorithm>
#include<string.h>
using namespace std;
#define oo 0x3f3f3f3f
#define maxn 105
#define maxm 11000
int dp[maxn][maxm];
struct EDGE
{
    int v,w,next;
}E[maxn<<1];
int val[maxn];
int dis[maxn],pre[maxn];
int mark[maxn],q[maxn],Front,Rear;
int head[maxn],tol;
int n,T;

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

void add_edge(int u,int v,int w)
{
    E[tol].v=v;
    E[tol].w=w;
    E[tol].next=head[u];
    head[u]=tol++;
}

int Spfa()
{
    for(int i=1;i<=n;i++)
    {
        dis[i]=oo;
        mark[i]=0;
    }
    dis[1]=0;mark[0]=1;
    Front=Rear=0;
    q[Rear++]=1;
    while(Front<Rear)
    {
        int u=q[Front++];
        mark[u]=0;
        for(int i=head[u];i!=-1;i=E[i].next)
        {
            int v=E[i].v;
            if(dis[u]+E[i].w<dis[v])
            {
                dis[v]=dis[u]+E[i].w;
                pre[v]=i;
                if(!mark[v])
                {
                    mark[v]=1;
                    q[Rear++]=v;
                }
            }
        }
    }
    return dis[n];
}

void Solve()
{
    for(int i=n;i!=1;i=E[pre[i]^1].v)
    {
       E[pre[i]].w=0;
    }
}

void Tree_dp(int u,int pre)
{
    for(int i=0;i<=n;i++)
        dp[u][i]=val[u];
    for(int i=head[u];i!=-1;i=E[i].next)
    {
        int v=E[i].v;
        if(v==pre) continue;
        Tree_dp(v,u);
        int w=E[i].w*2;
        for(int j=T;j>=w;j--)
            for(int k=0;k<=j-w;k++)
                dp[u][j]=max(dp[u][j],dp[u][j-k-w]+dp[v][k]);
    }
}

int main()
{
    int u,v,w,ans;
    while(scanf("%d %d",&n,&T)!=EOF)
    {
        inst();
        for(int i=1;i<=n-1;i++)
        {
            scanf("%d %d %d",&u,&v,&w);
            add_edge(u,v,w);
            add_edge(v,u,w);
        }
        for(int i=1;i<=n;i++)
            scanf("%d",&val[i]);
        int t=Spfa();
        if(t>T)
        {
            printf("Human beings die in pursuit of wealth, and birds die in pursuit of food!\n");
            continue;
        }
        T-=t;
        Solve();
        Tree_dp(1,-1);
        ans=0;
        for(int i=0;i<=T;i++)
            ans=max(dp[1][i],ans);
        printf("%d\n",ans);
    }
    return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值