HDU5834 Magic boy Bi Luo with his excited tree(树形DP)
题目
Source
http://acm.hdu.edu.cn/showproblem.php?pid=5834
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 you pass the edge i , you need to pay C[i].
You may attention that every V[i] can be taken only once, but for some C[i] , you may cost severial times.
Now, Bi Luo define ans[i] as the most value can Bi Luo gets if Bi Luo starts at node i.
Bi Luo is also an excited boy, now he wants to know every ans[i], can you help him?
Input
First line is a positive integer T(T≤104) , represents there are T test cases.
Four each test:
The first line contain an integer N(N≤105).
The next line contains N integers V[i], which means the treasure’s value of node i(1≤V[i]≤104).
For the next N−1 lines, each contains three integers u,v,c , which means node u and node v are connected by an edge, it's cost is c(1≤c≤104).
You can assume that the sum of N will not exceed 106.
Output
For the i-th test case , first output Case #i: in a single line , then output N lines , for the i-th line , output ans[i] in a single line.
Sample Input
1
5
4 1 7 7 7
1 2 6
1 3 1
2 4 8
3 5 2
Sample Output
Case #1:
15
10
14
9
15
分析
题目大概说给一棵树,点和边都有权值,经过一点可以加上该点的权值但最多只加一次,经过边会减去该边权值,问从各个点分别出发最多能获得多少权值。
这题是很裸的一种树形DP,做过类似HDU2196就知道怎么做了。两个DFS分别在O(n)处理出两种信息,各个结点往其为根的子树走的信息和各个结点往父亲走的信息,各个结点就能在O(1)合并这两个信息分别得出各个结点的最终信息。。
对于这题需要的状态是:
- dp_down[0/1][u]:u结点往其为根的子树走,并且不走回来/走回来,能得到的最大权值
- dp_up[0/1][u]:u结点往其父亲向上走,并且不走回来/走回来,能得到的最大权值
转移的话,想想就知道了。。dp_up[1][u]可以通过计算各个孩子信息的最大值和次大值求得,其他的比较简单,不过麻烦。。细节要注意,逻辑好考虑清楚。。比赛时我就没考虑好几个逻辑WA了,然后死活找不到错,还好队友A了。。
代码
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define MAXN 111111 struct Edge{
int v,w,next;
}edge[MAXN<<1];
int NE,head[MAXN];
void addEdge(int u,int v,int w){
edge[NE].v=v; edge[NE].w=w; edge[NE].next=head[u];
head[u]=NE++;
} int val[MAXN];
int d_down[2][MAXN],d_up[2][MAXN]; void dfs1(int u,int fa){
d_down[0][u]=d_down[1][u]=val[u];
for(int i=head[u]; i!=-1; i=edge[i].next){
int v=edge[i].v;
if(v==fa) continue;
dfs1(v,u);
if(d_down[0][v]-2*edge[i].w>0) d_down[0][u]+=d_down[0][v]-2*edge[i].w;
}
int mx=0;
for(int i=head[u]; i!=-1; i=edge[i].next){
int v=edge[i].v;
if(v==fa) continue;
if(d_down[0][v]-2*edge[i].w>0){
mx=max(mx,(d_down[1][v]-edge[i].w)-(d_down[0][v]-2*edge[i].w));
}else{
mx=max(mx,d_down[1][v]-edge[i].w);
}
}
d_down[1][u]=d_down[0][u]+mx;
}
void dfs2(int u,int fa){ int mx1=0,mx2=0,tmp;
for(int i=head[u]; i!=-1; i=edge[i].next){
int v=edge[i].v;
if(v==fa) continue;
if(d_down[0][v]-2*edge[i].w>0) tmp=(d_down[1][v]-edge[i].w)-(d_down[0][v]-2*edge[i].w);
else tmp=d_down[1][v]-edge[i].w;
if(mx1<tmp){
mx2=mx1;
mx1=tmp;
}else if(mx2<tmp){
mx2=tmp;
}
} for(int i=head[u]; i!=-1; i=edge[i].next){
int v=edge[i].v;
if(v==fa) continue; int tmp2;
if(d_down[0][v]-2*edge[i].w>0){
tmp2=d_down[0][u]-(d_down[0][v]-2*edge[i].w);
}else{
tmp2=d_down[0][u];
}
int mx=max(d_up[0][u]-2*edge[i].w,tmp2-2*edge[i].w);
mx=max(mx,d_up[0][u]+tmp2-2*edge[i].w-val[u]);
d_up[0][v]=val[v]+max(0,mx); if(d_down[0][v]-2*edge[i].w>0){
if(mx1==(d_down[1][v]-edge[i].w)-(d_down[0][v]-2*edge[i].w)) tmp=d_down[1][u]-(d_down[1][v]-edge[i].w)+mx2;
else tmp=d_down[1][u]-(d_down[0][v]-2*edge[i].w);
}else if(d_down[1][v]-edge[i].w>0){
if(mx1==d_down[1][v]-edge[i].w) tmp=d_down[1][u]-(d_down[1][v]-edge[i].w)+mx2;
else tmp=d_down[1][u];
}else tmp=d_down[1][u];
mx=max(d_up[1][u]-edge[i].w,tmp-edge[i].w);
mx=max(mx,max(d_up[0][u]+tmp-edge[i].w-val[u],d_up[1][u]+tmp2-edge[i].w-val[u]));
d_up[1][v]=val[v]+max(0,mx); dfs2(v,u);
}
} int main(){
int t;
scanf("%d",&t);
for(int cse=1; cse<=t; ++cse){
NE=0;
memset(head,-1,sizeof(head));
int n;
scanf("%d",&n);
for(int i=1; i<=n; ++i){
scanf("%d",val+i);
}
int a,b,c;
for(int i=1; i<n; ++i){
scanf("%d%d%d",&a,&b,&c);
addEdge(a,b,c);
addEdge(b,a,c);
}
dfs1(1,1);
d_up[0][1]=d_up[1][1]=val[1];
dfs2(1,1);
printf("Case #%d:\n",cse);
for(int i=1; i<=n; ++i){
printf("%d\n",max(d_up[0][i]+d_down[1][i],d_up[1][i]+d_down[0][i])-val[i]);
}
}
return 0;
}
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 Time Limit: 8000/4000 MS (Java/Others) Memory Limit: ...
- HDU5834 Magic boy Bi Luo with his excited tree (树形DP)
题意:一棵树有点权和边权 从每个点出发 走过一条边要花费边权同时可以获得点权 边走几次就算几次花费 点权最多算一次 问每个点能获得的最大价值 题解:好吧 这才叫树形DP入门题 dp[i][0]表示从i ...
- 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: 13107 ...
- 树形DP CCPC网络赛 HDU5834 Magic boy Bi Luo with his excited tree
// 树形DP CCPC网络赛 HDU5834 Magic boy Bi Luo with his excited tree // 题意:n个点的树,每个节点有权值为正,只能用一次,每条边有负权,可以 ...
- hdu5834 Magic boy Bi Luo with his excited tree 【树形dp】
题目链接 hdu5834 题解 思路很粗犷,实现很难受 设\(f[i][0|1]\)表示向子树走回来或不回来的最大收益 设\(g[i][0|1]\)表示向父亲走走回来或不回来的最大收益 再设\(h[i ...
- HDU5834Magic boy Bi Luo with his excited tree 树形dp
分析:典型的两遍dfs树形dp,先统计到子树的,再统计从祖先来的,dp[i][0]代表从从子树回来的最大值,dp[i][1]代表不回来,id[i]记录从i开始到哪不回来 吐槽:赛场上想到了状态,但是不 ...
- 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 migi ...
- 动态规划(树形DP):HDU 5834 Magic boy Bi Luo with his excited tree
aaarticlea/png;base64,iVBORw0KGgoAAAANSUhEUgAAA8UAAAJbCAIAAABCS6G8AAAgAElEQVR4nOy9fXQcxZ0uXH/hc8i5N+
- 【树形动规】HDU 5834 Magic boy Bi Luo with his excited tree
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5834 题目大意: 一棵N个点的有根树,每个节点有价值ci,每条树边有费用di,节点的值只能取一次,边 ...
随机推荐
- Codeforces Round #304 C(Div. 2)(模拟)
题目链接: http://codeforces.com/problemset/problem/546/C 题意: 总共有n张牌,1手中有k1张分别为:x1, x2, x3, ..xk1,2手中有k2张 ...
- android HTTPclient
Apache包是对android联网访问封装的很好的一个包,也是android访问网络最常用的类. 下面分别讲一下怎么用HttpClient实现get,post请求. 1.Get 请求 1 2 3 4 ...
- 快速反编绎jar war包
反编译这些class文件或jar包或war包,用TTools https://github.com/Supermax197/TTools [root@ok action]# tree /home/ok ...
- C语言中do...while(0)的妙用
在linux内核代码中,经常看到do...while(0)的宏,do...while(0)有很多作用,下面举出几个: 1.避免goto语句: 通常,如果一个函数开始要分配一些资源,然后如果在中途遇到错 ...
- Linux桌面选型
Arch Linux 官方仓库提供的桌面环境有 Cinnamon: cinnamon Enlightenment: enlightenment17 GNOME: gnome gnome-extra K ...
- Jquery自定义扩展方法(一)
jquery是一款流行的JS框架,自定义JS方法,封装到Jquery中,调用起来也挺方便的,怎么写Jquery扩展方法那,网上翻阅了一部分代码,其实也挺简单的: 方式一: (jQuery.fn.set ...
- 无废话ExtJs 入门教程九[数字字段:NumberField、隐藏字段Hidden、日期字段:DataFiedl]
无废话ExtJs 入门教程九[数字字段:NumberField.隐藏字段Hidden.日期字段:DataFiedl] extjs技术交流,欢迎加群(201926085) 继上第六节内容,我们在表单里加 ...
- Java程序员要求具备的10项技能
1.语法:必须比较熟悉,在写代码的时候IDE的编辑器对某一行报错应该能够根据报错信息知道是什么样的语法错误并且知道任何修正. 2.命令:必须熟悉JDK带的一些常用命令及其常用选项,命令至少需要熟悉:a ...
- 《图形学》实验四:中点Bresenham算法画直线
开发环境: VC++6.0,OpenGL 实验内容: 使用中点Bresenham算法画直线. 实验结果: 代码: //中点Bresenham算法生成直线 #include <gl/glut.h& ...
- Java 对象序列化(Serialization Object)
官网文档:https://docs.oracle.com/javase/tutorial/jndi/objects/serial.html 优秀博客: http://www.cnblogs.com/g ...