树形动规HDU 5834 Magic boy Bi Luo with his excited tree

Posted Coolxxx

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了树形动规HDU 5834 Magic boy Bi Luo with his excited tree相关的知识,希望对你有一定的参考价值。

题目链接:

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

题目大意:

  一棵N个点的有根树,每个节点有价值ci,每条树边有费用di,节点的值只能取一次,边权每次经过都要扣,问从每一个节点开始走最大能获得的价值。

题目思路:

  【树形动态规划】

  首先用dfs求出从根1往下走的:节点u往下走最后回到节点u的最大值g[u],节点u往下走最后不回到u的最优值和次优值f[0][u],f[1][u]

  接着考虑一个节点u,除了以上的情况还有可能是往它的父亲方向走,这里就分两种,一种是走父亲那边再回来走自己的子树,还有一种是走自己的子树再回来走父亲那边

  (肯定最后都不会特意回到u,因为边权>0,回到自己不会更优)而这些状态都可以通过dfs里求得f和g推出。

  具体推法我已写在代码注释中,希望没有写错。。

 

 

  1 //
  2 //by coolxxx
  3 //#include<bits/stdc++.h>
  4 #include<iostream>
  5 #include<algorithm>
  6 #include<string>
  7 #include<iomanip>
  8 #include<map>
  9 #include<stack>
 10 #include<queue>
 11 #include<set>
 12 #include<bitset>
 13 #include<memory.h>
 14 #include<time.h>
 15 #include<stdio.h>
 16 #include<stdlib.h>
 17 #include<string.h>
 18 //#include<stdbool.h>
 19 #include<math.h>
 20 #define min(a,b) ((a)<(b)?(a):(b))
 21 #define max(a,b) ((a)>(b)?(a):(b))
 22 #define abs(a) ((a)>0?(a):(-(a)))
 23 #define lowbit(a) (a&(-a))
 24 #define sqr(a) ((a)*(a))
 25 #define swap(a,b) ((a)^=(b),(b)^=(a),(a)^=(b))
 26 #define mem(a,b) memset(a,b,sizeof(a))
 27 #define eps (1e-8)
 28 #define J 10
 29 #define mod 1000000007
 30 #define MAX 0x7f7f7f7f
 31 #define PI 3.14159265358979323
 32 #define N 100004
 33 using namespace std;
 34 typedef long long LL;
 35 int cas,cass;
 36 int n,m,lll,ans;
 37 int w[N],last[N],g[N];
 38 int f[2][N],from[3][N],h[3][N];
 39 struct xxx
 40 {
 41     int next,to,d;
 42 }a[N+N];
 43 bool mark[N];
 44 void add(int x,int y,int z)
 45 {
 46     a[++lll].d=z;
 47     a[lll].to=y;
 48     a[lll].next=last[x];
 49     last[x]=lll;
 50 }
 51 void dfs(int u,int fa)//从根开始往下走的解
 52 {
 53     int i,j,v;
 54     g[u]=w[u];
 55     for(i=last[u];i;i=a[i].next)
 56     {
 57         v=a[i].to;
 58         if(v==fa)continue;
 59         dfs(v,u);
 60         g[u]+=max(0,g[v]-a[i].d-a[i].d);//g[u]统计最后回到u的最优解
 61     }
 62     for(i=last[u];i;i=a[i].next)
 63     {
 64         v=a[i].to;
 65         if(v==fa || f[0][v]<=a[i].d)continue;
 66         j=g[u]-max(0,g[v]-a[i].d-a[i].d)+max(0,f[0][v]-a[i].d);
 67         //枚举从u哪一条走下去不回,如果g[u]计算时有走v则要扣掉,再加上选择走v不回的最优值
 68         if(f[0][u]<=j)//不回u的最优值
 69         {
 70             f[1][u]=f[0][u],from[1][u]=from[0][u];
 71             f[0][u]=j,from[0][u]=i;
 72         }
 73         else if(f[1][u]<j)//不回u的次优值
 74             f[1][u]=j,from[1][u]=i;
 75     }
 76     f[0][u]=max(f[0][u],g[u]);
 77     f[1][u]=max(f[1][u],g[u]);
 78 }
 79 void work(int u,int fa)//计算最后答案
 80 {
 81     int i,j,v;
 82     for(i=last[u];i;i=a[i].next)
 83     {
 84         v=a[i].to;
 85         if(v==fa)return;
 86         j=max(0,g[v]-a[i].d-a[i].d);//u走到v再走回来是否更优
 87         h[0][v]=f[0][v]+max(0,g[u]-j-a[i].d-a[i].d);//g[u]扣除掉走v子树的值,先从v向上走到u再从u走回来,然后走回v的最优值
 88         h[1][v]=f[1][v]+max(0,g[u]-j-a[i].d-a[i].d);//次优值
 89         from[2][v]=i;
 90         if(g[v]>=a[i].d+a[i].d)//这种情况下前面多扣了一次边权
 91         {
 92             if(from[0][u]!=i)h[2][v]=h[0][u]+a[i].d;//v往上走回头再往下走不回头
 93             else h[2][v]=h[1][u]+a[i].d;//当前是最优值,选另一条走次优值
 94         }
 95         else//前面少扣了一次边权
 96         {
 97             if(from[0][u]!=i)h[2][v]=h[0][u]+g[v]-a[i].d;//v往下走回头再往上走不回头
 98             else h[2][v]=h[1][u]+g[v]-a[i].d;
 99         }
100         if(h[2][v]>h[1][v])swap(h[2][v],h[1][v]),swap(from[2][v],from[1][v]);
101         if(h[1][v]>h[0][v])swap(h[1][v],h[0][v]),swap(from[1][v],from[0][v]);
102         g[v]+=max(0,g[u]-j-a[i].d-a[i].d);//更新答案
103         work(v,u);
104     }
105 }
106 int main()
107 {
108     #ifndef ONLINE_JUDGE
109 //    freopen("1.txt","r",stdin);
110 //    freopen("2.txt","w",stdout);
111     #endif
112     int i,j,k;
113     int x,y,z;
114 //    for(scanf("%d",&cass);cass;cass--)
115     for(scanf("%d",&cas),cass=1;cass<=cas;cass++)
116 //    while(~scanf("%s",s+1))
117 //    while(~scanf("%d",&n))
118     {
119         mem(f,0);mem(from,0);mem(last,0);lll=0;
120         printf("Case #%d:\\n",cass);
121         scanf("%d",&n);
122         for(i=1;i<=n;i++)
123             scanf("%d",&w[i]);
124         for(i=1;i<n;i++)
125         {
126             scanf("%d%d%d",&x,&y,&z);
127             add(x,y,z);
128             add(y,x,z);
129         }
130         dfs(1,0);
131         h[0][1]=f[0][1],h[1][1]=f[1][1];
132         work(1,0);
133         for(i=1;i<=n;i++)
134             printf("%d\\n",h[0][i]);
135     }
136     return 0;
137 }
138 /*
139 //
140 
141 //
142 */
View Code

 

以上是关于树形动规HDU 5834 Magic boy Bi Luo with his excited tree的主要内容,如果未能解决你的问题,请参考以下文章

hdu5834 Magic boy Bi Luo with his excited tree 树形dp

HDU 5834 Magic boy Bi Luo with his excited tree (树形DP)

Magic boy Bi Luo with his excited tree (树形dp)

HDU 5834 [树形dp]

hdu5834

2016中国大学生程序设计竞赛 - 网络选拔赛 C. Magic boy Bi Luo with his excited tree