您的位置:首页 > 其它

HDU2196 Computer(树形dp经典)

2018-01-17 17:58 447 查看

Problem Description

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.

Input

Input 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.

Output

For 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

3
2
3
4
4


思路

这道题很巧妙,先说题意。

题目给了你一棵数,让你求出这棵树上的每个节点到叶子节点的最远距离。(树根为1)

说一下样例的给出方式:

首先是一个数n代表有n个节点,接下来有n−1行,每行两个数v,w,代表,第i+1个节点的父亲是v,这一条边的权值是w。让你输出树上的每个节点到叶子节点的最远距离。

题意现在很清楚了,现在我们来考虑做法,以下图为例(为了叙述方便,每条边的权值都是1):



对于
4
号节点,我们很容易看出,离他最远的叶子节点是
11
,距离为
5


对于
5
号节点,我们很容易看出,离他最远的叶子节点是
11
,距离为
3


对于
10
号节点,我们很容易看出,离他最远的叶子节点是
3
,距离为
5


我们很容易看出,离一个节点的最远的叶子节点,有不同的情况,通过观察发现,我们有3种不同的情况:

离当前节点最远的叶子节点在当前节点的子树中

离当前节点最远的叶子节点在当前节点的父亲的子树中

离当前节点的最远的叶子节点在当前节点的父亲的的父亲的子树中

对于上面的这些情况我们做出如下定义:

dp[i][0]—>以
i
为顶点(包括i)的子树中,所取得的最远距离

dp[i][1]—>以
i
的顶点的树取得的次远距离(次远距离上的点不可以包括最远距离上的点)

dp[i][2]—>从
i
节点往上找,它的先辈节点所能达到的最远距离

对于
dp[i][0]
我们可以通过一遍
dfs
来求出,假设当前搜索到了节点
u
u
v
的距离为
w
,我们找到
u
的子节点集
v{1,2,3,...}
从找出最大的dp[v][0]max,然后更新dp[u][0]=dp[v][0]max+w,在更新
dp[u][0]
的时候,我们同时也可以更新一下
dp[u][1]
,这样,通过一遍
dfs
就可以求出
dp[i][0]
dp[i][2]
的值。

那么
dp[i][2]
的值如何求,这时候我们刚才求出来的
dp[i][1]
就派上用场了,如上图,假设我们要求
dp[5][2]
的值,也就是5号节点的先辈所能打到的最远距离,5号节点的父亲是2号,那么我们可以先判断一下
dp[5][0]+w
是否等于
dp[2][0]
,如果相等,那么就说明5号节点在2号节点离叶子节点的最远路径上,那么我们所求的
dp[5][2]
肯定不能包括这一条路径,所以我们
dp[5][2]=max(dp[2][2],dp[2][1])
,反之
dp[5][2]=max(dp[2][2],dp[2][0])


当求出了
dp[i][2]
的值后,答案也就呼之欲出了,就是对于每个节点,求出
max(dp[i][0],dp[i][2])


代码

#include <cstdio>
#include <cstring>
#include <cctype>
#include <stdlib.h>
#include <string>
#include <map>
#include <iostream>
#include <stack>
#include <cmath>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;
typedef long long ll;
#define inf 0x3f3f3f3f
#define mem(a,b) memset(a,b,sizeof(a))
const int N=1e4+20;
int dp
[3];
int n;
int first
,pos;

struct edge
{
int v,w;
int next;
} G[2*N];

void add_edge(int u,int v,int w)
{
G[pos].v=v;
G[pos].w=w;
G[pos].next=first[u];
first[u]=pos++;
}
void init()
{
mem(first,-1);
mem(dp,0);
pos=0;
}

void dfs1(int u,int fa)
{
int ans1=0,ans2=0;//分别代表最大和和次大和
for(int i=first[u]; ~i; i=G[i].next)
{
int v=G[i].v;
if(v==fa)continue;
dfs1(v,u);
int res=dp[v][0]+G[i].w;
if(res>=ans1)
{
ans2=ans1;//先更新次大和
ans1=res;//再更新最大和
}
else if(res>ans2)
ans2=res;
}
dp[u][0]=ans1;
dp[u][1]=ans2;
}

void dfs2(int u,int fa)
{
for(int i=first[u]; ~i; i=G[i].next)
{
int v=G[i].v,w=G[i].w;
if(v==fa)continue;
if(dp[v][0]+w==dp[u][0])
dp[v][2]=max(dp[u][2],dp[u][1])+w;
else
dp[v][2]=max(dp[u][2],dp[u][0])+w;
dfs2(v,u);
}
}

int main()
{
int v,w;
while(~scanf("%d",&n))
{
init();
for(int u=2; u<=n; u++)
{
scanf("%d%d",&v,&w);
add_edge(u,v,w);
add_edge(v,u,w);
}
dfs1(1,-1);
dfs2(1,-1);
for(int i=1; i<=n; i++)
printf("%d\n",max(dp[i][0],dp[i][2]));
}
return 0;
}
/*
12
1 1
1 1
2 1
2 1
4 1
4 1
5 1
5 1
9 1
10 1
8 1
*/
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: