题意分析:
以树上每个点作为根,算出每个点作为根的最大深度,最大深度最小的点称为“好点”,深度最大的点称为“坏点”,输出所有的好点和所有的坏点。
解题思路:
这题只需要找到树上最远的两个端点,从这两个端点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; }