氪金带东

题目:氪金带东
题意:实验室里原先有一台电脑(编号为1),最近氪金带师咕咕东又为实验室购置了N-1台电脑,编号为2到N。每台电脑都用网线连接到一台先前安装的电脑上。但是咕咕东担心网速太慢,他希望知道第i台电脑到其他电脑的最大网线长度,但是可怜的咕咕东在不久前刚刚遭受了宇宙射线的降智打击,请你帮帮他。
在这里插入图片描述
提示: 样例输入对应这个图,从这个图中你可以看出,距离1号电脑最远的电脑是4号电脑,他们之间的距离是3。 4号电脑与5号电脑都是距离2号电脑最远的点,故其答案是2。5号电脑距离3号电脑最远,故对于3号电脑来说它的答案是3。同样的我们可以计算出4号电脑和5号电脑的答案是4.

输入:
输入文件包含多组测试数据。对于每组测试数据,第一行一个整数N (N<=10000),接下来有N-1行,每一行两个数,对于第i行的两个数,它们表示与i号电脑连接的电脑编号以及它们之间网线的长度。网线的总长度不会超过10^9,每个数之间用一个空格隔开。

输出:
对于每组测试数据输出N行,第i行表示i号电脑的答案 (1<=i<=N).

样例:
Sample Input
5
1 1
2 1
3 1
1 1
Sample Output
3
2
3
4
4

解题思路:首先,可以把这个图看成一个树;然后,树上的每个点距离最远的点一定是树的直径的两个点;这里给个证明:可以把树给展开,使其最长类似于:
在这里插入图片描述

可以很清楚的看出那个最长的边(这里假设边为1,边不为一同样可以这样做);如果某个点距离最长的点不是上图所示的左右两个端点,那么这个展开就不是最长的,这与展开是最长的矛盾,比如如果有个点的距离最远的点是上图分叉的那个小边的点,那么右端点肯定更远,这就产生了矛盾;就这样,先求出那个直径的两个端点,然后两边dfs,求出每个点到这两个端点的最大距离,这个距离就是那个要求的最大距离;

上代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#define ll long long
using namespace std;
struct node
{
    ll to;
    ll next;
    ll w;
}e[20005];
ll head[20005]={0},tot=0,vis[20005]={0},v1,v2,maxn=-1,d[20005]={0};
void chushihua()
{
    memset(head,0,sizeof(head));
    memset(vis,0,sizeof(vis));
    memset(d,0,sizeof(d));
    tot=0;
    maxn=-1;
}
void add(ll x,ll y,ll s)
{
    e[++tot].to=y;
    e[tot].next=head[x];
    e[tot].w=s;
    head[x]=tot;
}
void dfs(ll t,ll li)
{
    for(ll i=head[t];i;i=e[i].next)
    {
        ll x=e[i].to;
        if(vis[x]!=1)
        {
            ll h=li+e[i].w;
            vis[x]=1;
            if(maxn<h)
            {
                maxn=h;
                v1=x;
            }
            dfs(x,h);
        }
    }
}
void dfs1(ll t,ll li)
{
    for(ll i=head[t];i;i=e[i].next)
    {
        ll x=e[i].to;
        if(vis[x]!=1)
        {
            ll h=li+e[i].w;
            vis[x]=1;
            d[x]=max(d[x],h);
            dfs1(x,h);
        }
    }
}
int main()
{
    ll n;
    while(scanf("%lld",&n)!=EOF)
    {
        chushihua();//初始化
        for(ll i=2;i<=n;i++)//利用前向星存边
        {
            ll y,v;
            scanf("%lld%lld",&y,&v);
            add(i,y,v);
            add(y,i,v);
        }
        vis[1]=1;//先标记开始搜的点
        dfs(1,0);//先搜其中一个端点
        memset(vis,0,sizeof(vis));//初始化
        maxn=-1;
        v2=v1;
        vis[v2]=1;
        dfs(v2,0);//另外一个
        memset(vis,0,sizeof(vis));
        maxn=-1;
        vis[v1]=1;
        dfs1(v1,0);//遍历两边后就可以了;
        memset(vis,0,sizeof(vis));
        maxn=-1;
        vis[v2]=1;
        dfs1(v2,0);
        for(ll i=1;i<=n;i++)
        {
            printf("%lld\n",d[i]);
        }
    }
}
发布了34 篇原创文章 · 获赞 0 · 访问量 873

猜你喜欢

转载自blog.csdn.net/qq_43653717/article/details/105150916
今日推荐