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个点的树,每个节点有权值为正,只能用一次,每条边有负权,可以 ...
随机推荐
- 如何给Pycharm加上头行 # *_*coding:utf-8 *_*?
File>Setting>Editor>Code Style>File and Code Templates>Python Script 后面加上 # *_*codin ...
- shell基础:1.0概述
解释型.不用编译. 主要有两个工能:1.命令解释器 2.编程
- Linux编译安装中configure、make和make install各自的作用
这些都是典型的使用GNU的AUTOCONF和AUTOMAKE产生的程序的安装步骤. ./configure是用来检测你的安装平台的目标特征的.比如它会检测你是不是有CC或GCC,并不是需要CC或G ...
- mysql的转储SQL文件
1.转储数据库的SQL文件,有两个选择,一是转储结构:另一种是转储数据与结构: 2.以上两种转储都不会将事件(定时器)转储,所以特别注意这个,否则以为将数据库备份完了,其实漏掉了所有的事件代码,所以需 ...
- windows上mysql的配置文件my.ini内容
# Other default tuning values# MySQL Server Instance Configuration File# --------------------------- ...
- Python:slice与indices
slice: eg: >>>e=[0,1,2,3,4,5,6] >>>s=slice(2,3) >>>e[s] [2] slice的区间左闭右开[ ...
- vim的简单配置
本文大部分内容转载自:https://blog.csdn.net/lhy2932226314/article/details/69668891 vim是从 vi 发展出来的一个文本编辑器.功能丰富,在 ...
- linux常用命令:scp 命令
scp(secure copy)用于进行远程文件拷贝. 1.命令格式: scp [参数] [源文件] [目标文件] 2.命令功能: scp在主机间复制文件,他使用 ssh(1)作为数据传输,而且用同样 ...
- Linux基础命令---dumpe2fs
dumpe2fs 显示ext2.ext3.ext4文件系统的超级快和块组信息.此命令的适用范围:RedHat.RHEL.Ubuntu.CentOS.SUSE.openSUSE.Fedora. 1.语法 ...
- MySQL数据库----函数
函数 MySQL中提供了许多内置函数,例如: CHAR_LENGTH(str) 返回值为字符串str 的长度,长度的单位为字符.一个多字节字符算作一个单字符. 对于一个包含五个二字节字符集, LENG ...