HDU 5834 Magic boy Bi Luo with his excited tree(树形dp)
http://acm.hdu.edu.cn/showproblem.php?pid=5834
题意:
一棵树上每个节点有一个价值$Vi$,每个节点只能获得一次,每走一次一条边要花费$Ci$,问从各个节点出发最多能收获多少价值。
思路:
需要考虑子节点和父亲节点两个方面。既然是这样,那就需要两次dfs来解决问题了,$dp[u][0]$表示从u出发最后还是回到u的最大价值和,$dp[u][1]$表示从u出发最后不回到u的最大价值和。
第一次dfs很显然就是计算出每个节点往其子树方向的$dp[u][0]$和$dp[u][1]$值。
第二次dfs就是再去考虑每个节点加上其父节点的情况,这里就需要维护一个最大值和一个次大值了,为什么呢?因为父节点的最大值可能最后停在了v子树,那么v子树到时候再去考虑父节点的时候就不对了,所以此时要将它改成次大值,这样它的最大值最后不会停在v子树。
总而言之,这是一道很经典的树形dp,不过没写出来。。
#include<iostream>
#include<algorithm>
#include<cstring>
#include<cstdio>
#include<vector>
#include<stack>
#include<queue>
#include<cmath>
#include<map>
#include<set>
using namespace std;
typedef long long ll;
typedef pair<int,int> pll;
const int INF = 0x3f3f3f3f;
const int maxn=1e5+; int n;
int val[maxn];
int dp[maxn][];
vector<pll> G[maxn]; void dfs1(int u, int fa) //求出每个顶点往子树方向的最大值,dp[u][0]表示最终回到u,dp[u][1]表示最终不回到u
{
dp[u][]=dp[u][]=val[u];
for(int i=;i<G[u].size();i++)
{
int v=G[u][i].first;
int w=G[u][i].second;
if(v==fa) continue;
dfs1(v,u);
if(dp[v][]-*w>) dp[u][]+=dp[v][]-*w;
}
for(int i=;i<G[u].size();i++)
{
int v=G[u][i].first;
int w=G[u][i].second;
if(v==fa) continue;
int tmp = dp[u][]-max(,dp[v][]-*w)+(dp[v][]-w);
if(dp[u][]<tmp) dp[u][]=tmp;
}
} void dfs2(int u, int fa, int cost) //处理往父亲节点的方向
{
int dir_tree=u;
if(fa!=-) if(dp[fa][]-*cost>) dp[u][]+=dp[fa][]-*cost;
int sub_large=dp[u][]=dp[u][];
for(int i=;i<G[u].size();i++)
{
int v=G[u][i].first;
int w=G[u][i].second;
int tmp=dp[u][]-max(,dp[v][]-*w)+(dp[v][]-w);
if(tmp>=dp[u][]) //计算最大权值和次大权值
{
sub_large=dp[u][];
dp[u][]=tmp;
dir_tree=v;
}
else if(tmp>=sub_large) sub_large=tmp;
}
int pre0=dp[u][],pre1=dp[u][]; //出去该父节点对其子节点的影响
for(int i=;i<G[u].size();i++)
{
int v=G[u][i].first;
int w=G[u][i].second;
if(v==fa) continue;
int tmp=dp[v][]-*w;
if(tmp>) dp[u][]-=tmp; //子节点v往父节点走时,肯定不会再算v节点的子树
if(dir_tree==v) dp[u][]=sub_large; //如果u的最大值最后停留在v子树,则改成次大值
if(tmp>) dp[u][]-=tmp; //和上面的第2句相同
dfs2(v,u,w);
dp[u][]=pre0,dp[u][]=pre1;
} } int main()
{
//freopen("in.txt","r",stdin);
int T;
int kase=;
scanf("%d",&T);
while(T--)
{
scanf("%d",&n);
for(int i=;i<=n;i++) {G[i].clear();scanf("%d",&val[i]);}
for(int i=;i<n;i++)
{
int u,v,w;
scanf("%d%d%d",&u,&v,&w);
G[u].push_back(make_pair(v,w));
G[v].push_back(make_pair(u,w));
}
printf("Case #%d:\n",++kase);
dfs1(,-);
dfs2(,-,);
for(int i=;i<=n;i++) printf("%d\n",dp[i][]);
}
return ;
}
HDU 5834 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: 13107 ...
- 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: ...
- 【树形动规】HDU 5834 Magic boy Bi Luo with his excited tree
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=5834 题目大意: 一棵N个点的有根树,每个节点有价值ci,每条树边有费用di,节点的值只能取一次,边 ...
- 动态规划(树形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
树形dp. 先dfs一次处理子树上的最优解,记录一下回到这个点和不回到这个点的最优解. 然后从上到下可以推出所有答案.细节较多,很容易写错. #pragma comment(linker, " ...
- HDU5834 Magic boy Bi Luo with his excited tree (树形DP)
题意:一棵树有点权和边权 从每个点出发 走过一条边要花费边权同时可以获得点权 边走几次就算几次花费 点权最多算一次 问每个点能获得的最大价值 题解:好吧 这才叫树形DP入门题 dp[i][0]表示从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 CCPC网络赛 HDU5834 Magic boy Bi Luo with his excited tree
// 树形DP CCPC网络赛 HDU5834 Magic boy Bi Luo with his excited tree // 题意:n个点的树,每个节点有权值为正,只能用一次,每条边有负权,可以 ...
随机推荐
- jmeter之Java request报错:java.lang.NoClassDefFoundError: redis/clients/jedis/Jedis
今天在学习Jmeter的java request,请求内容是连接redis并获取其中的一个字段值.结果在运行时报如下错误: 2018/05/24 13:08:20 ERROR - jmeter.thr ...
- 使用SolrJ代码导入,发布搜索服务
搭建solr服务器:http://www.cnblogs.com/liyafei/p/8005571.html 一导入要搜索的字段 1:确定发布搜索的字段,sql语句 SELECT a.id, b. ...
- POJ3414—Pots(bfs加回溯)
http://poj.org/problem?id=3414 Pots Time Limit: 1000MS Memor ...
- jenkins 项目发布脚本
构建shell #!/bin/bash ########################################################################## 编译部分 ...
- for和foreach的区别
public class Program { public static void Main() { Program program = new Program(); program.For();// ...
- 复习一下property
在面向对象程序里,一个对象不要直接访问另一个对象内部的数据.所以我们使用accessor methods来进行对象内部的数据交互. accessor methods(getters and sette ...
- Must be between v0 and v15, inclusive解决办法
invoke-static 改为invoke-static/range
- Javascript-逻辑或(||)
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...
- source的简单操作
source五部曲 git工作流:建立新功能 更改文件后,提交 点击git工作流完成新功能 点击推送 点击拉取
- 519. Random Flip Matrix(Fisher-Yates洗牌算法)
1. 问题 给定一个全零矩阵的行和列,实现flip函数随机把一个0变成1并返回索引,实现rest函数将所有数归零. 2. 思路 拒绝采样 (1)先计算矩阵的元素个数(行乘以列),记作n,那么[0, n ...