[UVA 10459]The Tree Root[树上最长距离]

题目链接: [UVA 10459]The Tree Root[树上最长距离]

题意分析:

以树上每个点作为根,算出每个点作为根的最大深度,最大深度最小的点称为“好点”,深度最大的点称为“坏点”,输出所有的好点和所有的坏点。

解题思路:

这题只需要找到树上最远的两个端点,从这两个端点dfs更新每个点到这两个端点之一的最大距离即可。

用到的结论是:最长距离,一定是该点和这两个端点其中之一之间的最大距离。

可以用反证法:假设存在一个点X,让该点到点X的距离大于上方提及的两个端点,那么这个点就能和上两个端点之一组成新的最远端点,就会导致上方两个点不是最远的端点,矛盾。

个人感受:

一直想着从某个点dfs,然后记录距离,想着怎么复用这个数据,无果= =。这个新姿势真心赞~

具体代码如下:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<queue>
using namespace std;

const int INF = 0x7f7f7f7f;
const int MAXN = 1e5 + 111;

int dis[MAXN], mxdep, ed;
vector<vector<int> > G;

void dfs(int u, int fa, int dep)
{
    if (dep > mxdep) mxdep = dep, ed = u;
    for (int i = 0; i < G[u].size(); ++i)
    {
        int v = G[u][i];
        if (v == fa) continue;
        dfs(v, u, dep + 1);
        dis[v] = max(dis[v], dep + 1);
    }
}

int main()
{
    int n, cnt, x;
    while (~scanf("%d", &n))
    {
        G.clear();
        G.resize(n + 2);
        memset(dis, 0, sizeof(int) * (n + 2));

        for (int i = 1; i <= n; ++i)
        {
            scanf("%d", &cnt);
            for (int j = 0; j < cnt; ++j)
            {
                scanf("%d", &x);
                G[i].push_back(x);
            }
        }

        mxdep = 0;
        dfs(1, -1, 0);      // 找到最远端点
        dfs(ed, -1, 0);     // 计算所有点到该端点距离,并查找另一个端点
        dfs(ed, -1, 0);     // 所有点到该端点的距离

        int mi = INF;
        for (int i = 1; i <= n; ++i) mi = min(mi, dis[i]);

        printf("Best Roots  :");
        for (int i = 1; i <= n; ++i) if (dis[i] == mi) printf(" %d", i);
        puts("");

        printf("Worst Roots :");
        for (int i = 1; i <= n; ++i) if (dis[i] == mxdep) printf(" %d", i);
        puts("");
    }
    return 0;
}


你可能感兴趣的:(树)