HDU 2196 Computer 树上最长距离

该博客介绍了如何解决树形网络结构中计算每个节点最远距离的问题。通过证明树上任意节点的最远距离一定对应树直径的端点,提出了采用两次DFS遍历的方法来找到这两个端点,并计算所有节点到它们的最大距离。

题意:一个树形的网络传输结构,求出每个节点的最远距离。
思路:
首先有一个结论:树上任意一个节点的最远距离对应的节点,一定是树的直径的两个端点之一。
证明如下:
设树的直径的两个端点为u,v,设任意一点为w。
1.当w位于uv 的路径上时,w的最远距离对应的点显然是点u或者是点v.
2.当w不在uv 的路径上时,我们利用反证法来证明上面的结论。
假设w的最远距离对应的点是s,则L ws >L wv  
必然可以找到一个点t,在wt 的路径上,路径wv 和路径ws 是重合的。

L ws >L wv  

L wt +L ts >L wt +L tv  

L ts >L tv  

我们再引入直径的另外一点u
L ut +L ts >L ut +L tv  

L us >L uv  

uv 为树的直径相矛盾。
所以假设不成立。

这样利用上面的结论,选取任意节点为根,一遍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;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值