HDU4276(The Ghost Blows Light T时间入口1 出口n 问可得的最大价值 树形dp)

题目
在这里插入图片描述
题意: 你在一座古墓里盗墓,古墓在T分钟时就会倒塌,你就挂了。古墓有n个房间,每个房间都有一定价值的宝藏,n-1条边,每条边有花费的时间,形成一棵树。如果逃不出去就输出… 如果能逃出去,那么输出能获得的最大价值是多少?
思路: 先dfs算出1-n路径需要的时间tmp tmp<T就不能逃出古墓。
假如可以逃出古墓。那么把1-n的路径的边长设为0,然后问题就转化为K-(1-n路径花的时间)时间内1-任意点再回到1点 可得到的最大价值是多少。
仔细想想,这个模型的转化是正确的,很好。
poj3345的弱化版

#include<cstdio>
#include<iostream>
#include<cstring>
#define m(a,b) memset(a,b,sizeof a)
using namespace std;
typedef long long ll;
const int N=500+5,INF=0x3f3f3f3f;
struct Edge{int to,nex,len;}edge[N<<1];int head[N],tot;
inline void add(int from,int to,int len){
    edge[++tot]=(Edge){to,head[from],len},head[from]=tot;
    edge[++tot]=(Edge){from,head[to],len},head[to]=tot;
}
int val[N],dp[N][N],n,K;
int dfs(int x,int fa){
    if(x==n) return 0;
    for(int i=head[x];i;i=edge[i].nex){
        int y=edge[i].to,w=edge[i].len;
        if(y==fa) continue;
        int tmp=dfs(y,x);
        if(tmp!=-1){
            edge[i].len=0;//其实只edge[i].len=0 因为dfs dfs2的顺序是一样的
            return tmp+w;
        }
    }
    return -1;
}
void dfs2(int x,int fa){
    for(int i=0;i<=K;++i) dp[x][i]=dp[x][i]=val[x];
    for(int i=head[x];i;i=edge[i].nex){
        int y=edge[i].to,w=edge[i].len;
        if(y==fa) continue;
        dfs2(y,x);
        for(int j=K;j>=0;--j)
            for(int k=0;k<=j;++k)//k要从0开始 因为w可以为0  2*w就可以为0
                if(k>=2*w) dp[x][j]=max(dp[x][j],dp[y][k-2*w]+dp[x][j-k]);
    }
}
int main(){
    while(~scanf("%d%d",&n,&K)){
        m(head,0),tot=1;
        for(int i=1,x,y,w;i<n;++i) scanf("%d%d%d",&x,&y,&w),add(x,y,w);
        for(int i=1;i<=n;++i) scanf("%d",&val[i]);
        K-=dfs(1,1);
        if(K<0) {puts("Human beings die in pursuit of wealth, and birds die in pursuit of food!");continue;}
        m(dp,0),dfs2(1,1);
        printf("%d\n",dp[1][K]);
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值