hdu4276 树形dp

25 篇文章 0 订阅

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

Problem Description

My name is Hu Bayi, robing an ancient tomb in Tibet. The tomb consists of N rooms (numbered from 1 to N) which are connected by some roads (pass each road should cost some time). There is exactly one route between any two rooms, and each room contains some treasures. Now I am located at the 1st room and the exit is located at the Nth room. 
Suddenly, alert occurred! The tomb will topple down in T minutes, and I should reach exit room in T minutes. Human beings die in pursuit of wealth, and birds die in pursuit of food! Although it is life-threatening time, I also want to get treasure out as much as possible. Now I wonder the maximum number of treasures I can take out in T minutes.
 

Input
There are multiple test cases.
The first line contains two integer N and T. (1 <= n <= 100, 0 <= T <= 500)
Each of the next N - 1 lines contains three integers a, b, and t indicating there is a road between a and b which costs t minutes. (1<=a<=n, 1<=b<=n, a!=b, 0 <= t <= 100)
The last line contains N integers, which Ai indicating the number of treasure in the ith room. (0 <= Ai <= 100)
 

Output
For each test case, output an integer indicating the maximum number of treasures I can take out in T minutes; if I cannot get out of the tomb, please output "Human beings die in pursuit of wealth, and birds die in pursuit of food!".
 

Sample Input
  
  
5 10 1 2 2 2 3 2 2 5 3 3 4 3 1 2 3 4 5
 

Sample Output
  
  
11
 

Source


/**
hdu4276   树形dp
题目大意:给定一个n节点的树,从1到n去每条路耗费一定的时间,每经过一个点就可以获得这一点的能量值,问如何在T时间内能到达n点并且获得的能量值尽量多
解题思路:先dfs找出1到n的路径(肯定唯一),凡是在这条路上的边到必走且只要走一遍,其他的边要走的话,那么都要走两次(终点始终是n)我们把dfs出来的
           路径全部置零,T-=该路径权值和。然后dp[u][j]表示以u为节点的子树在j时间内可获得的能量值,用背包就可以解决了,不过边的权值都要*2后计算,
           并且子节点到达的前提是父亲节点已经到达。因此状态转移方程为:
           dp[u][j]=max(dp[u][j],dp[u][j-2*w-k]+dp[v][k]);(j:w*2~T)(k:0~j-2*w)w为边权值
*/
#include <stdio.h>
#include <string.h>
#include <algorithm>
#include <iostream>
using namespace std;
const int maxn=105;

struct note
{
    int v,w,next;
}edge[maxn*2];

int head[maxn],ip;
int m,n,sum,dp[maxn][550],a[maxn];

void init()
{
    memset(head,-1,sizeof(head));
    ip=0;
}

void addedge(int u,int v,int w)
{
    edge[ip].v=v,edge[ip].w=w,edge[ip].next=head[u],head[u]=ip++;
}

bool dfs(int u,int pre)///找出1~n的路径
{
    if(u==n)return true;
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(v==pre)continue;
        if(dfs(v,u))
        {
            sum+=edge[i].w;
            edge[i].w=0;
            return true;
        }
    }
    return false;///这句话必须有,因为这一句我没写WA到死.....
}
void get(int u,int pre)///输出该树
{
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        if(v==pre)continue;
        printf("%d->%d:%d\n",u,v,edge[i].w);
        get(v,u);
    }
}

void dfs1(int u,int pre)
{
    for(int i=0;i<=m;i++)
         dp[u][i]=a[u];
    for(int i=head[u];i!=-1;i=edge[i].next)
    {
        int v=edge[i].v;
        int w=edge[i].w;
        if(v==pre)continue;
        dfs1(v,u);
        for(int j=m;j>=2*w;j--)
        {
            for(int k=0;k+2*w<=j;k++)
            {
                dp[u][j]=max(dp[u][j],dp[u][j-2*w-k]+dp[v][k]);
            }
        }
    }
}
int main()
{
    while(~scanf("%d%d",&n,&m))
    {
        init();
        for(int i=0;i<n-1;i++)
        {
            int u,v,w;
            scanf("%d%d%d",&u,&v,&w);
            addedge(u,v,w);
            addedge(v,u,w);
        }
        for(int i=1;i<=n;i++)
        {
            scanf("%d",&a[i]);
        }
        sum=0;
        dfs(1,-1);
      ///  get(1,-1);
        m-=sum;
        if(m<0)
        {
            printf("Human beings die in pursuit of wealth, and birds die in pursuit of food!\n");
            continue;
        }
      ///  printf("%d\n",sum);
        memset(dp,0,sizeof(dp));
        dfs1(1,-1);
        printf("%d\n",dp[1][m]);
    }
    return 0;
}


  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值