Week6:氪金带东——树的直径

题目描述
实验室里原先有一台电脑(编号为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).

输入案例

5
1 1
2 1
3 1
1 1

输出样例

3
2
3
4
4

解题思路
给定一颗树,求树的直径,树的直径被定义为树中任意两点之间距离的最
大值。首先明确一点是树的直径一定是某两个叶子之间的距离。从树中任选一个点开始遍历这棵树,找到一个距离这个点最远的叶子,然后再从这个叶子开始遍历,找到离这个叶子最远的另一个叶子,他俩之间的距离就是树的直径。两次遍历即可求的树的直径。
大概思路类似于,平面几何中,要找到直径,先随便取圆内一点,然后找到圆中距离这个点距离最远的点(肯定在边上,对应上述的树的叶子节点上),然后以这个最远的点开始,找离这个点的最远的另一个点,肯定也在圆的边上,这两点连线就是直径,且可得证这是圆内最长的一条线段(废话)。

注意:上述只是一个用来理解的思路。

这道题不是找最长路径(树的直径),而是找某个节点x所能到达的最长路径。
首先这个节点x的最长路径要么是到v1的路径,要么就是到v2的路径。
所以我们找到v1和v2之后,再跑一次遍历就能找到每个点到v1/v2的距离了,求两者最大值就是答案。

贴出代码:

#include <iostream>
#include <vector>
#include <cstring>

using namespace std;

struct Edge
{
    int u, v, w;
    Edge(int u,int v, int w):u(u),v(v),w(w){}

};

vector<Edge>edge[10005];
bool visit[10005];
int dis[10005];
int themax;

void dfs(int point, int& ans, int& r1)
{
    for (int i = 0; i < edge[point].size(); i++)
    {
        int v = edge[point][i].v;
        if (!visit[v])
        {
            visit[v] = true;
            int w = edge[point][i].w;
            ans += w;
            if (ans > themax)
            {
                themax = ans;
                r1 = v;
            }
            dfs(v, ans, r1);
            ans -= w;
        }
    }
}

void GetAns(int point,int nowlength)
{
    for (int i = 0; i < edge[point].size(); i++)
    {
        int v = edge[point][i].v;
        if (!visit[v])
        {
            visit[v] = true;
            int w = edge[point][i].w;
            nowlength += w;
            if (nowlength > dis[v])
            {
                dis[v] = nowlength;
            }
            GetAns(v, nowlength);
            nowlength -= w;
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0);

    int n;
    while (cin >> n)
    {
        memset(dis, 0, sizeof dis);//初始化答案数组
        for (int i = 0; i < 10005; i++) edge[i].clear();

        int v, w;
        for (int i = 2; i <= n; i++)
        {
            cin >> v >> w;
            edge[i].push_back(Edge(i, v, w));
            edge[v].push_back(Edge(v, i, w));
        }

        memset(visit, false, sizeof visit);
        visit[1] = true;
        int ans = 0, r1 = 1;
        themax = 0;
        dfs(1, ans, r1);

        memset(visit, false, sizeof visit);
        visit[r1] = true;
        ans = 0;
        int r2 = r1;
        themax = 0;
        dfs(r1, ans, r2);

        memset(visit, false, sizeof visit);
        visit[r1] = true;
        GetAns(r1, 0);

        memset(visit, false, sizeof visit);
        visit[r2] = true;
        GetAns(r2, 0);

        for (int i = 1; i <= n; i++)
        {
            cout << dis[i] << endl;
        }
    }



    return 0;

}
发布了21 篇原创文章 · 获赞 3 · 访问量 404

猜你喜欢

转载自blog.csdn.net/qq_44506233/article/details/105282455