zoukankan      html  css  js  c++  java
  • HDU 4276 The Ghost Blows Light (树形DP)

    The Ghost Blows Light

    Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
    Total Submission(s): 1410    Accepted Submission(s): 420


    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
     
    Recommend
    liuyiding

    题目:给出一棵树,从1走到n,总时间为T,每走一条边需要花费一定时间,每个结点有一定价值,问在指定时间内回到T的能获取的最大价值

    首先dfs或者spfa求一次最短路,如果从1到n的最短花费都小于总时间,则是不可能。

    而且在最短路的时候记录每个节点的父节点,以及边的编号

    然后将最短路径上的所有边权置为0.将总时间减去最短路径。

    这样处理的目的是,显然最短路上的边只会走一遍才是最优的,而且剩下的边要么不走,要么走两次,而且DFS求一次树形DP之后,不需要考虑回到n的情况,因为1-n的最短路径走了一遍,其它边走0次或两次,肯定是回到n的。

    #include<iostream>
    #include<cstdio>
    #include<cstring>
    
    using namespace std;
    
    const int VM=120;
    
    struct Edge{
        int to,nxt;
        int cap;
    }edge[VM<<1];
    
    int n,T,cnt,head[VM];
    int dp[VM][520],val[VM];    //dp[i][j]表示从第i个点开始,回到i点,花费j时间得到的最大财富值
    
    void addedge(int cu,int cv,int cw){
        edge[cnt].to=cv;
        edge[cnt].cap=cw;
        edge[cnt].nxt=head[cu];
        head[cu]=cnt++;
    }
    
    int time1;
    
    int DFS1(int u,int pre){    //找从1到N的最短时间
        if(u==n)
            return 1;
        for(int i=head[u];i!=-1;i=edge[i].nxt){
            int v=edge[i].to;
            if(v==pre)
                continue;
            if(DFS1(v,u)){
                time1+=edge[i].cap;
                edge[i].cap=0;
                return 1;
            }
        }
        return 0;
    }
    /*
    
    void spfa(int s){
        queue<int>que;
        int vis[N];
        mem(vis,0);mem(pre,0);
        for(int i=1;i<=n;i++)
            if(i==s)
                dist[i]=0;
            else
                dist[i]=inf;
        que.push(s);
        vis[s]=1;
        while(!que.empty()){
            int u=que.front();
            que.pop();
            vis[u]=0;
            for(int i=start[u];i!=-1;i=edge[i].next){
                int v=edge[i].v,w=edge[i].w;
                if(dist[v]>dist[u]+w){
                    dist[v]=dist[u]+w;
                    pre[v]=u;
                    p[v]=i;
                    if(!vis[v]){
                        vis[v]=1;
                        que.push(v);
                    }
                }
            }
        }
        for(int i=n;i!=1;i=pre[i]){
            edge[p[i]].w=0;
            edge[p[i]^1].w=0;
        }
    }
    
    */
    
    void DFS2(int u,int pre){
        for(int i=0;i<=T;i++)
            dp[u][i]=val[u];
        for(int i=head[u];i!=-1;i=edge[i].nxt){
            int v=edge[i].to;
            if(v==pre)
                continue;
            DFS2(v,u);
            int cost=edge[i].cap*2; //要走两遍
            for(int j=T;j>=cost;j--)
                for(int k=0;k<=j-cost;k++)
                    dp[u][j]=max(dp[u][j],dp[v][k]+dp[u][j-cost-k]);
        }
    }
    
    int main(){
    
        //freopen("input.txt","r",stdin);
    
        while(~scanf("%d%d",&n,&T)){
            cnt=0;
            memset(head,-1,sizeof(head));
            int u,v,w;
            for(int i=1;i<n;i++){
                scanf("%d%d%d",&u,&v,&w);
                addedge(u,v,w);
                addedge(v,u,w);
            }
            for(int i=1;i<=n;i++)
                scanf("%d",&val[i]);
            time1=0;
            DFS1(1,-1);
            if(T<time1){
                printf("Human beings die in pursuit of wealth, and birds die in pursuit of food!\n");
                continue;
            }
            T-=time1;
            DFS2(1,-1);
            printf("%d\n",dp[1][T]);
        }
        return 0;
    }
  • 相关阅读:
    安装VMware,出现Microsoft Runtime DLL 安装程序未能完成安装,解决方法
    linux mysql udf 提权
    XXE漏洞学习
    了解Metasploit中的Payloads(有效载荷)
    Metasploit 如何使用Exploits(漏洞)
    Metasploit 使用MSFconsole接口
    Metasploit 模块和位置
    Nmap速查手册
    Linux常用命令大全(非常全!!!)
    Web中常见的绕过和技巧
  • 原文地址:https://www.cnblogs.com/jackge/p/3091309.html
Copyright © 2011-2022 走看看