题意:一个树形的网络传输结构,求出每个节点的最远距离。
思路:
首先有一个结论:树上任意一个节点的最远距离对应的节点,一定是树的直径的两个端点之一。
证明如下:
设树的直径的两个端点为u,v,设任意一点为w。
1.当w位于u→v 的路径上时,w的最远距离对应的点显然是点u或者是点v.
2.当w不在u→v 的路径上时,我们利用反证法来证明上面的结论。
假设w的最远距离对应的点是s,则L w→s >L w→v
必然可以找到一个点t,在w→t 的路径上,路径w→v 和路径w→s 是重合的。
则
L w→s >L w→v
L w→t +L t→s >L w→t +L t→v
L t→s >L t→v
我们再引入直径的另外一点u
L u→t +L t→s >L u→t +L t→v
L u→s >L u→v
和u→v 为树的直径相矛盾。
所以假设不成立。
这样利用上面的结论,选取任意节点为根,一遍DFS就能求出直径的一个端点,然后从这个端点再次DFS就能求出另外一个端点,最远距离每个节点到两个端点距离的最大值。
代码如下:
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int MAX = 10010;
struct edge{
int to,w;
edge(){}
edge(int t, int ww):to(t),w(ww){}
} edges[MAX<<1];
int N;
int nxt[MAX<<1],head[MAX],tot;
int dp1[MAX],dp2[MAX];
void init()
{
memset(head,-1,sizeof(head));
tot = 0;
}
void addedge(int u, int v, int w)
{
edges[tot] = edge(v,w);
nxt[tot] = head[u];
head[u] = tot++;
}
void dfs(int u, int p, int d, int* dis)
{
dis[u] = d;
for(int i = head[u]; ~i; i = nxt[i]){
edge & e = edges[i];
if(e.to == p) continue;
dfs(e.to,u,d+e.w,dis);
}
}
int main(void)
{
//freopen("input.txt","r",stdin);
while(scanf("%d",&N) != EOF){
init();
for(int i = 2; i <= N; ++i){
int v,w;
scanf("%d%d",&v,&w);
addedge(i,v,w);
addedge(v,i,w);
}
dfs(1,0,0,dp1);
int poi1 = 1, len = 0;
for(int i = 1; i <= N; ++i){
if(dp1[i] > len){
len = dp1[i];
poi1 = i;
}
}
dfs(poi1,0,0,dp1);
int poi2 = 1;len = 0;
for(int i = 1; i <= N; ++i){
if(dp1[i] > len){
len = dp1[i];
poi2 = i;
}
}
dfs(poi2,0,0,dp2);
for(int i = 1; i <= N; ++i)
printf("%d\n",max(dp1[i],dp2[i]));
}
return 0;
}
该博客介绍了如何解决树形网络结构中计算每个节点最远距离的问题。通过证明树上任意节点的最远距离一定对应树直径的端点,提出了采用两次DFS遍历的方法来找到这两个端点,并计算所有节点到它们的最大距离。

310

被折叠的 条评论
为什么被折叠?



