zoukankan      html  css  js  c++  java
  • HDU4276 The Ghost Blows Light(树形DP+背包)

    题目大概说一棵n个结点树,每个结点都有宝藏,走过每条边要花一定的时间,现在要在t时间内从结点1出发走到结点n,问能获得最多的宝藏是多少。

    放了几天的题,今天拿出来集中精力去想,还是想出来了。

    首先,树上任意两点间最短的那条路径是唯一的,且不管怎么走一定都会走过那条路径上的所有点,也就是说整个行程可以看成两部分组成:一部分就是1到n的最短路径,另一部分就是从这个路径上的某点出发绕回该点的路径。

    这样问题就清晰了,现在关键在求第二部分:

    • 先用树上背包求出:dp[u][t],表示从在以u点为根的子树中从u点出发且不经过n结点及其祖先结点最后回到u点总共用时t能获得最多的宝藏
    • 最后从1到n最短的那条路径上的各个点u看作物品,有t种规格的体积,每种体积价值是dp[u][t],背包容量为总时间-走那条最短路所需时间,这样再做一次背包,求出装满某体积(用某时间)能得到的最大价值就OK了。
    • 注意的是那个状态是不经过n结点及其祖先结点,这是为了不重复统计,1到n路径上的点本身就是父子关系。
     1 #include<cstdio>
     2 #include<cstring>
     3 #include<algorithm>
     4 using namespace std;
     5 #define MAXN 111
     6 struct Edge{
     7     int v,w,next;
     8 }edge[MAXN<<1];
     9 int NE,head[MAXN];
    10 void addEdge(int u,int v,int w){
    11     edge[NE].v=v; edge[NE].w=w; edge[NE].next=head[u];
    12     head[u]=NE++;
    13 }
    14 int n,t,val[MAXN],d[MAXN][555],par[MAXN],weight[MAXN];
    15 bool dp(int u){
    16     bool flag=0;
    17     d[u][0]=val[u];
    18     for(int i=head[u]; i!=-1; i=edge[i].next){
    19         int v=edge[i].v;
    20         if(v==par[u]) continue;
    21         par[v]=u;
    22         weight[v]=edge[i].w;
    23         if(dp(v)){
    24             flag=1;
    25             continue;
    26         }
    27         for(int j=t; j>=0; --j){
    28             for(int k=0; ; ++k){
    29                 if(edge[i].w*2+k>j) break;
    30                 if(d[v][k]==-1 || d[u][j-edge[i].w*2-k]==-1) continue;
    31                 d[u][j]=max(d[u][j],d[u][j-edge[i].w*2-k]+d[v][k]);
    32             }
    33         }
    34     }
    35     if(u==n) return 1;
    36     return flag;
    37 }
    38 int rec[MAXN],rn,tot;
    39 void dfs(int u){
    40     if(u!=1){
    41         tot+=weight[u];
    42         dfs(par[u]);
    43     }
    44     rec[rn++]=u;
    45 }
    46 int ans[MAXN][555];
    47 int main(){
    48     int a,b,c;
    49     while(~scanf("%d%d",&n,&t)){
    50         NE=0;
    51         memset(head,-1,sizeof(head));
    52         for(int i=1; i<n; ++i){
    53             scanf("%d%d%d",&a,&b,&c);
    54             addEdge(a,b,c);
    55             addEdge(b,a,c);
    56         }
    57         for(int i=1; i<=n; ++i) scanf("%d",val+i);
    58         memset(d,-1,sizeof(d));
    59         dp(1);
    60         rn=tot=0;
    61         dfs(n);
    62         tot=t-tot;
    63         memset(ans,-1,sizeof(ans));
    64         for(int i=0; i<=tot; ++i) ans[0][i]=d[rec[0]][i];
    65         for(int i=1; i<rn; ++i){
    66             for(int j=0; j<=tot; ++j){
    67                 for(int k=0; k<=tot; ++k){
    68                     if(j+k>tot || ans[i-1][j]==-1 || d[rec[i]][k]==-1) continue;
    69                     ans[i][j+k]=max(ans[i][j+k],ans[i-1][j]+d[rec[i]][k]);
    70                 }
    71             }
    72         }
    73         int res=-1;
    74         for(int i=0; i<=tot; ++i) res=max(res,ans[rn-1][i]);
    75         if(res==-1) puts("Human beings die in pursuit of wealth, and birds die in pursuit of food!");
    76         else printf("%d
    ",res);
    77     }
    78     return 0;
    79 }
  • 相关阅读:
    N++ 道ASP.NET面试题
    Console-算法:fun1(do while)
    软件业:印度比中国强在哪
    印度软件业崛起的奥妙
    算法目录
    scala目录
    scala命令
    Spark目录
    Ubuntu目录
    Java核心技术卷二部分笔记
  • 原文地址:https://www.cnblogs.com/WABoss/p/5330337.html
Copyright © 2011-2022 走看看