题目链接:
[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;
}