HDU 5834 Magic boy Bi Luo with his excited tree

题目:Magic boy Bi Luo with his excited tree

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

题意:给一棵树,在树的每个结点可以收获一定的积分,每一条边会消耗一定的积分,每个结点积分取一次便完,但每次路过一条边,都会消耗积分,问从每一个结点出发,最多能捞多少积分。N范围10万,样例数1万。

思路:

  不难的一道题,但细节较多,容易出错。

  树形DP。

  从i 点出发,大致可以分为向上 和 向下两种,先考虑向下的情况。可以想到,假设i 连着n 条边,那么如果要想把n 条边外的积分都拿到手,那么n 条边,有n-1 条边要走两次。那么,我们可以设置dp 如下:

  dp[i]:从i 出发,又回到i 的最优解

  fen[i][0]:从i 出发,不回到i 的最优解  -----  fen[i][1]:最终朝着哪个边离开

  fen[i][2]:从i 出发,不回到i 的次优解

  对i 结点,我们需要的信息就是上面4 个,一次dfs可以求出。

  对根节点rt,他的答案ans[rt] = fen[rt][0]。对于中间的某个结点x,ans[x] 是两种情况取最大,一:从i 出发,往上方走,又回到i ,再往下方走(不回来了),其中往下方走不回来就是fen[x][0],往上方走又回来(暂放)。二:从i 出发,往下方走,又回到i ,再往上方走(不回来),这里往下方走又回来就是dp[x],往上方走不会来(暂放)。

  上面这一步中dfs要传两个参数(up1,up2),up1表示往上方走不回来的最优解,up2表示往上方走又回来的最优解。现在我们来解决这两个参数,在x 点时,对于x 的某个孩子son ,e是x 和son 连接的边,假如这个son 就是fen[x][1],那么fen[x][2]-max(0,dp[son]-2*e)就代表了从x 出发,不往son 方向走又不回来的最优解,如果son 不是fen[x][1],那么这个最优解就是fen[x][0]-max(0,dp[son]-2*e),而up1代表了从x 出发,往上方走,不回来的最优解,那么要想两者都得到,要么往上方走回来(up2),要么往下方走回来(dp[x]-max(0,dp[son]-2*e)),这两个可以取最优解,就可以得到son 的up1、up2参数(up1要减去e,up2要减去2e)。

提供一组数据:

2
5
1 2 2 2 2
1 2 1
1 3 1
3 4 3
3 5 3
7
1 4 1 7 6 9 8
1 2 2
1 3 1
2 4 3
2 5 4
3 6 6
3 7 7

答案为:

1.  2  3  3  2  2

2.  7  8  7  10  10  10  8

我在倒二个10 弄了半天,一直显示9 ,搞了半天

AC代码:

 1 #include<stdio.h>
 2 #include<string.h>
 3 #include<vector>
 4 #include<algorithm>
 5 using namespace std;
 6 #define N 100010
 7 vector<pair<int,int> > v[N];
 8 int w[N];   //w[i] : 点i 的权值
 9 int dp[N];  //dp[i] : 从i 往下走,又回到i 的最大收获
10 int fen[N][3];
11 /*
12   fen[i][0] : 从i 出发,不回到i 的最大收获
13   fen[i][1] : 从i 出发,不回到i 的最大收获 的 最后路径(就是不重复两次的那条)
14   fen[i][2] : 从i 出发,不回到i 的次大收获
15 */
16 void dfs(int rt,int fa)
17 {
18   dp[rt]=w[rt];
19   for(int i=0;i<v[rt].size();i++)
20   {
21     if(v[rt][i].first==fa) continue;
22     dfs(v[rt][i].first,rt);
23     dp[rt] += max(0 , dp[v[rt][i].first] - 2*v[rt][i].second);
24   }
25   fen[rt][1]=-1;
26   fen[rt][0]=fen[rt][2]=w[rt];
27   for(int i=0;i<v[rt].size();i++)
28   {
29     int ad=v[rt][i].first;
30     int wa=v[rt][i].second;
31     if(ad==fa) continue;
32     int now = dp[rt] - max(0 , dp[ad]-2*wa) + max(0 , fen[ad][0]-wa);
33     // now 就是从这条路径出发不回来的收获
34     if(now>fen[rt][0])
35     {
36       fen[rt][2]=fen[rt][0];
37       fen[rt][0]=now;
38       fen[rt][1]=i;
39     }
40     else if(now>fen[rt][2]) fen[rt][2]=now;
41   }
42 }
43 int ans[N];
44 void dfs2(int rt,int fa,int up1,int up2)
45 {//up1 : rt父结点出去不回来的最优解 up2 : rt父结点出去又回到父结点的最优解
46   ans[rt]=max(dp[rt]+up1,up2+fen[rt][0]);
47
48   for(int i=0;i<v[rt].size();i++)
49   {
50     int ad=v[rt][i].first;
51     int wa=v[rt][i].second;
52     if(ad==fa) continue;
53     int down1,down2;
54     if(fen[rt][1]==i) down1=max(0 , fen[rt][2] - max(0,dp[ad]-2*wa));
55     else down1=max(0 , fen[rt][0] - max(0,dp[ad]-2*wa));
56     down2=max(0 , dp[rt] - max(0,dp[ad]-2*wa));
57     down1=max(0 , max(up1+down2-wa,up2+down1-wa));
58     down2=max(0 , up2+down2-2*wa);
59     dfs2(ad,rt,down1,down2);
60   }
61 }
62 int main()
63 {
64   int t,n,x,y,z,cas=1;
65   scanf("%d",&t);
66   while(t--)
67   {
68     scanf("%d",&n);
69     for(int i=1;i<=n;i++) scanf("%d",&w[i]);
70     for(int i=1;i<n;i++)
71     {
72       scanf("%d%d%d",&x,&y,&z);
73       v[x].push_back(make_pair(y,z));
74       v[y].push_back(make_pair(x,z));
75     }
76     dfs(1,0);
77     dfs2(1,0,0,0);
78     printf("Case #%d:\n",cas++);
79     for(int i=1;i<=n;i++) printf("%d\n",ans[i]);
80     for(int i=1;i<=n;i++) v[i].clear();
81   }
82   return 0;
83 }
时间: 2024-12-25 23:01:08

HDU 5834 Magic boy Bi Luo with his excited tree的相关文章

hdu 5834 Magic boy Bi Luo with his excited tree 树形dp+转移

Magic boy Bi Luo with his excited tree Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others)Total Submission(s): 1058    Accepted Submission(s): 308 Problem Description Bi Luo is a magic boy, he also has a migic tree,

【树形动规】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,除了以上的情况还有可能是往它的父亲方向走,这

动态规划(树形DP):HDU 5834 Magic boy Bi Luo with his excited tree

非常难想的树形DP. 1 #include <iostream> 2 #include <cstring> 3 #include <cstdio> 4 using namespace std; 5 const int N=100010; 6 int cnt,fir[N],nxt[N*2],to[N*2],val[N*2]; 7 int n,w[N],ans[N],fa[N],f1[N][2],f2[N][2]; 8 void addedge(int a,int b,in

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

题意:给定一棵树,每个点有个权值,每条边有权值,每经过边都会消耗相应的权值,但是点的权值只能获得一次,问你从 i 点出发能获得的最大权值是多少. 析:树形DP,就是太麻烦了,两次dfs,维护一共6个值分别是,从 i 出发的最大值并且返回 i, 从 i 出发的最大值并且不返回,从 i 出发的次大值并且不返回,从 i 出发的最大值的子树结点并且不返回,从 i 向父结点出发的最大值并且不返回,从 i 向父结点出发的最大值并且返回. 第一次dfs就能求出前四个,第二个dfs维护后面两个. 答案就是  m

【HDOJ 5834】Magic boy Bi Luo with his excited tree(树型DP)

[HDOJ 5834]Magic boy Bi Luo with his excited tree(树型DP) Magic boy Bi Luo with his excited tree Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Problem Description Bi Luo is a magic boy, he also has a migic tree,

树形DP CCPC网络赛 HDU5834 Magic boy Bi Luo with his excited tree

1 // 树形DP CCPC网络赛 HDU5834 Magic boy Bi Luo with his excited tree 2 // 题意:n个点的树,每个节点有权值为正,只能用一次,每条边有负权,可以走多次,问从每个点出发的最大获益 3 // 思路: 4 // dp[i]: 从i点出发回到i点的最大值 5 // d[i][0] 从i点出发不回来的最大值 6 // d[i][1] 从i点出发取最大值的下一个点 7 // d[i][2] 从i点出发取次大值 8 // dfs1处理出这四个 9

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

Magic boy Bi Luo with his excited tree Time Limit: 8000/4000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Others) Total Submission(s): 723    Accepted Submission(s): 192 Problem Description Bi Luo is a magic boy, he also has a migic tree,

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

Magic boy Bi Luo with his excited tree Problem Description Bi Luo is a magic boy, he also has a migic tree, the tree has N nodes , in each node , there is a treasure, it's value is V[i], and for each edge, there is a cost C[i], which means every time

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

Bi Luo is a magic boy, he also has a migic tree, the tree has NN nodes , in each node , there is a treasure, it's value is V[i]V[i], and for each edge, there is a cost C[i]C[i], which means every time you pass the edge ii , you need to pay C[i]C[i].