HDU - 2196(树形DP)
题目:
Hint: the example input is corresponding to this graph. And from the graph, you can see that the computer 4 is farthest one from 1, so S1 = 3. Computer 4 and 5 are the farthest ones from 2, so S2 = 2. Computer 5 is the farthest one from 3, so S3 = 3. we also get S4 = 4, S5 = 4.
InputInput file contains multiple test cases.In each case there is natural number N (N<=10000) in the first line, followed by (N-1) lines with descriptions of computers. i-th line contains two natural numbers - number of computer, to which i-th computer is connected and length of cable used for connection. Total length of cable does not exceed 10^9. Numbers in lines of input are separated by a space.OutputFor each case output N lines. i-th line must contain number Si for i-th computer (1<=i<=N).Sample Input
5
1 1
2 1
3 1
1 1
Sample Output
2
3
4
4 题意:
不知道多少组测试样例,第一行一个n,代表有多少台电脑,接下来有n-1行,每行两个数a,b,第i行(2<=i<=n)表示编号为i的电脑连接编号为a的电脑,他们的距离是b(即电缆长度),问每台电脑到其最远点距离 思路:树形DP(感谢大佬的视频讲解 https://www.bilibili.com/video/av12194537?t=1863)
我们定义f【i】表示编号为i的节点第一步向儿子方向走的最远距离
g【i】表示编号为i的节点第一步向父亲方向走的最远距离
p【i】表示编号为i的节点的父亲节点编号
w(a,b)表示编号a节点到编号b节点的距离,a和b是一条边连接的,即边权
用2个dfs求出这三个数组
递推式:f【u】=max(f【v】,w(u,v))//v是u的孩子
g【u】=w(u,p【u】)+max(g【p【u】】,f【v】+w(p【u】,u))//v是u的兄弟
两个递推式在下面讲解
对于第i个节点,答案就是max(f【i】,g【i】)
因为对一个节点来说,它的第一步只能是向孩子方向走(可能有多个孩子)或者向父亲方向走 第一遍dfs求出f和p数组,我们默认1节点是根节点,它的父亲节点是0(假想)
这个深搜很容易理解,直接上代码
long long int dfs1(int u,int fa)
{//u节点走孩子方向的最大距离
for(int i=;i<E[u].size();++i){
int v=E[u][i].first;
int w=E[u][i].second;
if(v!=fa)
f[u]=max(f[u],dfs1(v,p[v]=u)+w);
/*要么是当前值(可能有多个孩子),要么是当前点到孩子点的距离加上f【v】*/
}
return f[u];
}
第二遍dfs求出g数组,看图(假设边权都为1)
图中红色数字为节点编号,黑色数字表示f【u】的值(第一遍dfs求出),即当前节点第一步向孩子方向走的最大距离
第一遍dfs,相当于从下往上进行动态规划,而第二遍dfs,则是从上往下进行动态规划
怎么用f和p数组算出g数组呢
假设我们要求节点u的g,令fa是u节点的父亲节点
首先,g【u】=g【fa】(假设第一步往上走且第二步也是往上走的距离最大)
然后遍历fa连接的所有节点
若找到fa的父亲节点,跳过,因为我们一开始就假设走这条路
若找到u节点,跳过,跑回来干嘛
若找到其他节点(必然为u节点的兄弟节点,我们设为v,v可能有多个,也可能没有)
则比较g【u】和w(fa,v)+f【v】的大小,即比较第二步往上走好一点还是往下走好一点
遍历完之后,g【u】加上w(fa,u),就成功把g【u】算出来了
我们看出,要想求g【u】,就要先知道g【fa】,即要先知道上面节点的g,才能求下面节点的g
所以,这是一个从上往下走的过程
对于根节点的计算,我们不存在w(0,1)所以还要注意一下边界问题
代码实现:
void dfs2(int u,int fa)
{
int t=;
g[u]=g[fa];
for(int i=;i<E[fa].size();++i){
int v=E[fa][i].first;
int w=E[fa][i].second;
if(v==p[fa]) continue;//fa的父亲节点,跳过
if(v==u) t=w;//又跑回来了,跳过
else g[u]=max(g[u],f[v]+w);//更新
}
g[u]+=t;
for(int i=;i<E[u].size();++i){//dfs孩子节点,更新下面的g
int v=E[u][i].first;
int w=E[u][i].second;
if(v!=fa) dfs2(v,u);
}
}
我们模拟跑一下dfs2,从根节点开始
首先g【1】=g【0】=0;然后编号0节点是虚拟的,没有连接任何点,所以g【1】=0;
求节点2,g【2】=g【1】=0;然后遍历编号1节点连接的所有点
找到节点2,跳过,找到节点3,更新g【2】=max(g【2】,w(1,3)+f【3】)=max(0,1+0)=1;
遍历完后,我们加上w(1,2)=1,所以g【2】=1+1=2;
求节点4,g【4】=g【2】=2;然后遍历编号2节点连接的所有点
找到节点1,1是2的父亲节点,跳过
找到节点4,跳过
找到节点5,更新g【4】=max(g【4】,w(2,5)+f【5】)=max(2,1+1)=2;
遍历完后,我们加上w(2,4)=1,所以g【4】=2+1=3;
......
这样就更新好了g数组
然后答案就是max(f【i】,g【i】)啦,第一步要么向孩子方向走,要么向父亲方向走,找二者最大就行了
完整代码:
#include <bits/stdc++.h>
#define mp make_pair
using namespace std;
typedef long long int ll;
const int maxn=1e5+;
vector<pair<int,int> > E[maxn];
long long int f[maxn],g[maxn],p[maxn];
long long int dfs1(int u,int fa)
{//u节点走孩子方向的最大距离
for(int i=;i<E[u].size();++i){
int v=E[u][i].first;
int w=E[u][i].second;
if(v!=fa)
f[u]=max(f[u],dfs1(v,p[v]=u)+w);
}
return f[u];
}
void dfs2(int u,int fa)
{
int t=;
g[u]=g[fa];
for(int i=;i<E[fa].size();++i){
int v=E[fa][i].first;
int w=E[fa][i].second;
if(v==p[fa]) continue;
if(v==u) t=w;
else g[u]=max(g[u],f[v]+w);
}
g[u]+=t;
for(int i=;i<E[u].size();++i){
int v=E[u][i].first;
int w=E[u][i].second;
if(v!=fa) dfs2(v,u);
}
} int main()
{
int n;
while(cin>>n)
{
for(int i=;i<=n;++i)
E[i].clear();
memset(f,,sizeof(f));
memset(g,,sizeof(g));
memset(p,,sizeof(p));
for(int i=;i<=n;++i){
int a,b;
scanf("%d%d",&a,&b);
E[a].push_back(mp(i,b));
E[i].push_back(mp(a,b));
}
dfs1(,);
dfs2(,);
for(int i=;i<=n;++i){
printf("%lld\n",max(f[i],g[i]));
}
}
return ;
}
HDU - 2196(树形DP)的更多相关文章
- HDU 2196树形DP(2个方向)
HDU 2196 [题目链接]HDU 2196 [题目类型]树形DP(2个方向) &题意: 题意是求树中每个点到所有叶子节点的距离的最大值是多少. &题解: 2次dfs,先把子树的最大 ...
- HDU 2196 树形DP Computer
题目链接: HDU 2196 Computer 分析: 先从任意一点开始, 求出它到其它点的最大距离, 然后以该点为中心更新它的邻点, 再用被更新的点去更新邻点......依此递推 ! 代码: ...
- hdu 2196 树形dp
思路:先求以1为根时,每个节点到子节点的最大长度.然后再次从1进入进行更新. #include<iostream> #include<cstring> #include< ...
- hdu 4123 树形DP+RMQ
http://acm.hdu.edu.cn/showproblem.php? pid=4123 Problem Description Bob wants to hold a race to enco ...
- HDU 1520 树形dp裸题
1.HDU 1520 Anniversary party 2.总结:第一道树形dp,有点纠结 题意:公司聚会,员工与直接上司不能同时来,求最大权值和 #include<iostream> ...
- HDU 1561 树形DP入门
The more, The Better Time Limit: 6000/2000 MS (Java/Others) Memory Limit: 32768/32768 K (Java/Oth ...
- HDU 1520 树形DP入门
HDU 1520 [题目链接]HDU 1520 [题目类型]树形DP &题意: 某公司要举办一次晚会,但是为了使得晚会的气氛更加活跃,每个参加晚会的人都不希望在晚会中见到他的直接上司,现在已知 ...
- codevs 1380/HDU 1520 树形dp
1380 没有上司的舞会 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 回到问题 题目描述 Description Ural大学有N个职员 ...
- HDU 5834 [树形dp]
/* 题意:n个点组成的树,点和边都有权值,当第一次访问某个点的时候获得利益为点的权值 每次经过一条边,丢失利益为边的权值.问从第i个点出发,获得的利益最大是多少. 输入: 测试样例组数T n n个数 ...
- hdu 4267 树形DP
思路:先dfs一下,找出1,n间的路径长度和价值,回溯时将该路径长度和价值清零.那么对剩下的图就可以直接树形dp求解了. #include<iostream> #include<al ...
随机推荐
- Mysql备份恢复方案解析
1.全量备份和增量备份 1.1全量备份 就是对现有的数据进行全部备份,之前做的备份均可舍弃,以最新的全备为基点. a.全备所有数据库 Innodb引擎: [root@leader mysql]#mys ...
- FOFA 批量采集url 图形化界面编写
这是脚本 # coding:utf- import requests,re import time import sys import getopt import base64 guizhe='' s ...
- Ubuntu下Nginx的安装和卸载
环境是Ubuntu 16.04 安装: sudo apt-get update sudo apt-get install nginx 卸载: sudo apt-get --purge remove n ...
- Maven:element '******' cannot have character [children]
此错误是由于XML文件的解析不正确造成的,因为在一个/某些标签之间存在奇怪和隐藏的字符. 这些字符可能来自网络上的复制粘贴.要解决此问题,请删除标签>标记定义之间的所有空格和换行符,然后将它们放 ...
- git如何配置邮箱和用户名?
答: 1. 配置邮箱 git config --global user.email "jello_smith@163.com" 2. 配置用户名 git config --glob ...
- python从入门到放弃之anconada真愁人
原先未使用anconada,用的python2.7,每次install各种包各种问题真的心累 后来装了anconada,安装了python3.6 使用起来比较方便了. 陆续将遇到的问题更新如下~ 一 ...
- android java.lang.IllegalArgumentException: Comparison method violates its general contract! 问题
android java.lang.IllegalArgumentException: Comparison method violates its general contract! 问题 jav ...
- MySQL中tinytext、text、mediumtext和longtext等各个类型详解
转: MySQL中tinytext.text.mediumtext和longtext等各个类型详解 2018年06月13日 08:55:24 youcijibi 阅读数 26900更多 个人分类: 每 ...
- mfc通过信号量保证线程同步
1.声明一个全局handle,记住在cpp里也声明 extern HANDLE uiHandle; 2.创建信号量 uiHandle = CreateSemaphore(NULL,1,1,NULL); ...
- HDFS的NameNode与SecondaryNameNode的工作原理
原文:https://blog.51cto.com/xpleaf/2147375 看完之后确实对nameNode的工作更加清晰一些 在Hadoop中,有一些命名不好的模块,Secondary Name ...