题目:

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. Mysql备份恢复方案解析

    1.全量备份和增量备份 1.1全量备份 就是对现有的数据进行全部备份,之前做的备份均可舍弃,以最新的全备为基点. a.全备所有数据库 Innodb引擎: [root@leader mysql]#mys ...

  2. FOFA 批量采集url 图形化界面编写

    这是脚本 # coding:utf- import requests,re import time import sys import getopt import base64 guizhe='' s ...

  3. Ubuntu下Nginx的安装和卸载

    环境是Ubuntu 16.04 安装: sudo apt-get update sudo apt-get install nginx 卸载: sudo apt-get --purge remove n ...

  4. Maven:element '******' cannot have character [children]

    此错误是由于XML文件的解析不正确造成的,因为在一个/某些标签之间存在奇怪和隐藏的字符. 这些字符可能来自网络上的复制粘贴.要解决此问题,请删除标签>标记定义之间的所有空格和换行符,然后将它们放 ...

  5. git如何配置邮箱和用户名?

    答: 1. 配置邮箱 git config --global user.email "jello_smith@163.com" 2. 配置用户名 git config --glob ...

  6. python从入门到放弃之anconada真愁人

    原先未使用anconada,用的python2.7,每次install各种包各种问题真的心累 后来装了anconada,安装了python3.6 使用起来比较方便了. 陆续将遇到的问题更新如下~  一 ...

  7. android java.lang.IllegalArgumentException: Comparison method violates its general contract! 问题

    android  java.lang.IllegalArgumentException: Comparison method violates its general contract! 问题 jav ...

  8. MySQL中tinytext、text、mediumtext和longtext等各个类型详解

    转: MySQL中tinytext.text.mediumtext和longtext等各个类型详解 2018年06月13日 08:55:24 youcijibi 阅读数 26900更多 个人分类: 每 ...

  9. mfc通过信号量保证线程同步

    1.声明一个全局handle,记住在cpp里也声明 extern HANDLE uiHandle; 2.创建信号量 uiHandle = CreateSemaphore(NULL,1,1,NULL); ...

  10. HDFS的NameNode与SecondaryNameNode的工作原理

    原文:https://blog.51cto.com/xpleaf/2147375 看完之后确实对nameNode的工作更加清晰一些 在Hadoop中,有一些命名不好的模块,Secondary Name ...