题目:

A school bought the first computer some time ago(so this computer's id is 1). During the recent years the school bought N-1 new computers. Each new computer was connected to one of settled earlier. Managers of school are anxious about slow functioning of the net and want to know the maximum distance Si for which i-th computer needs to send signal (i.e. length of cable to the most distant computer). You need to provide this information. 

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)的更多相关文章

  1. HDU 2196树形DP(2个方向)

    HDU 2196 [题目链接]HDU 2196 [题目类型]树形DP(2个方向) &题意: 题意是求树中每个点到所有叶子节点的距离的最大值是多少. &题解: 2次dfs,先把子树的最大 ...

  2. HDU 2196 树形DP Computer

    题目链接:  HDU 2196 Computer 分析:   先从任意一点开始, 求出它到其它点的最大距离, 然后以该点为中心更新它的邻点, 再用被更新的点去更新邻点......依此递推 ! 代码: ...

  3. hdu 2196 树形dp

    思路:先求以1为根时,每个节点到子节点的最大长度.然后再次从1进入进行更新. #include<iostream> #include<cstring> #include< ...

  4. hdu 4123 树形DP+RMQ

    http://acm.hdu.edu.cn/showproblem.php? pid=4123 Problem Description Bob wants to hold a race to enco ...

  5. HDU 1520 树形dp裸题

    1.HDU 1520  Anniversary party 2.总结:第一道树形dp,有点纠结 题意:公司聚会,员工与直接上司不能同时来,求最大权值和 #include<iostream> ...

  6. HDU 1561 树形DP入门

    The more, The Better Time Limit: 6000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Oth ...

  7. HDU 1520 树形DP入门

    HDU 1520 [题目链接]HDU 1520 [题目类型]树形DP &题意: 某公司要举办一次晚会,但是为了使得晚会的气氛更加活跃,每个参加晚会的人都不希望在晚会中见到他的直接上司,现在已知 ...

  8. codevs 1380/HDU 1520 树形dp

    1380 没有上司的舞会 时间限制: 1 s 空间限制: 128000 KB 题目等级 : 钻石 Diamond 题解 查看运行结果 回到问题 题目描述 Description Ural大学有N个职员 ...

  9. HDU 5834 [树形dp]

    /* 题意:n个点组成的树,点和边都有权值,当第一次访问某个点的时候获得利益为点的权值 每次经过一条边,丢失利益为边的权值.问从第i个点出发,获得的利益最大是多少. 输入: 测试样例组数T n n个数 ...

  10. hdu 4267 树形DP

    思路:先dfs一下,找出1,n间的路径长度和价值,回溯时将该路径长度和价值清零.那么对剩下的图就可以直接树形dp求解了. #include<iostream> #include<al ...

随机推荐

  1. python常用模块(不定期更新)

    前言: 随着python开发项目越来越大,显然应该把不同功能的代码放到不同的.py文件里,每一个.py文件叫一个模块:模块分为(1)内置标准模块(2)第三方模块(3)自定义模块 这三种.这篇博客就是用 ...

  2. Java并发指南3:并发三大问题与volatile关键字,CAS操作

    本文转载自互联网,侵删   序言 先来看如下这个简单的Java类,该类中并没有使用任何的同步. 01 final class SetCheck { 02 private int  a = 0; 03 ...

  3. Microsoft Office-未响应

    默认打印机的配置可能与 Word.Excel 打开文件一操作就未响应有关 今天写点文档突然发现 Word.Excel 打开文件一操作就未响应,新建一个文件编辑倒是没有问题,很奇怪.搜到的博客基本全是由 ...

  4. windows 下OPENSSL 生成秘钥和公钥的方法

    1. 生成原始 RSA私钥文件 private_key.pem openssl genrsa -out private_key.pem 1024 2. 将原始 RSA私钥转换为 pkcs8格式 ope ...

  5. windows7导入k8s用户证书

    通过浏览器访问 需要给浏览器生成一个 client 证书,访问 apiserver 的 6443 https 端口时使用 这里使用部署 kubectl 命令行工具时创建的 admin 证书.私钥和上面 ...

  6. php错误机制总结

    转 http://www.cnblogs.com/yjf512/p/5314345.html

  7. js 匿名函数 js-函数定义方法

    1.任何函数都是有返回值的,没有返回值的,在某些语言里称之为过程例如PL/SQL 2.js中的函数如果没有return 关键字指明给出的返回值,那么当调用完函数后,会返回“undefined" ...

  8. ulimt 和 sysctl

    ulimit : 对进程进行 资源限制 ,如打开文件数,进程数. sysctl: 更改内核参数. /proc/pid : 伪文件系统,以文件系统的方式 对 访问内核参数 提供接口. 1. ulimit ...

  9. 牛客竞赛(gcd,快速幂)

    一.最大公约数和最小公倍数问题 题目描述: 输入2个正整数x0,y0(2<=x0<100000,2<=y0<=1000000),求出满足下列条件的P,Q的个数. 条件:1.P, ...

  10. python之pandas学习笔记-初识pandas

    初识pandas python最擅长的就是数据处理,而pandas则是python用于数据分析的最常用工具之一,所以学python一定要学pandas库的使用. pandas为python提供了高性能 ...