??从树上找三个点,它们之间的边集最大。
??假设\(a,b,c\)三点连接在同一个点\(z\)上面,那么要想得到最大的边集,\(a,b\)两点肯定是离\(z\)点最远的两个点,而\(c\)点肯定是离\(a,b\)最远的点,按照树的直径的定义,其中两个点之间的简单路径必定是这棵树的直径。求出来树的直径然后找一个点到这个直径两个端点的距离最远就行了。
??可以先跑一个\(dfs\),求树的直径的第一个端点\(a\),然后再以\(a\)点为根跑\(dfs\)得到另外一个端点\(b\),以及所有点到\(a\)的距离,最后跑一遍\(dfs\)求所有点到\(b\)的距离。这样处理之后,我们枚举所有与\(a\)和\(b\)不同的点找一个到这两个点最远的点就行了。
const int maxn = 2e5+10;
vector<int> e[maxn];
int disx[maxn] = {-1}, disy[maxn] = {-1}, tmp;
//https://www.cnblogs.com/shuitiangong/
void dfs(int p, int u, int *dis) {
dis[u] = dis[p]+1;
for (auto v : e[u])
if (v != p) dfs(u, v, dis);
if (dis[tmp]<dis[u]) tmp = u;
}
int main(void) {
int n;
scanf("%d", &n);
for (int i = 0, u, v; i<n-1; ++i) {
scanf("%d%d", &u, &v);
e[u].push_back(v);
e[v].push_back(u);
}
dfs(0, 1, disy); int x = tmp; tmp = x;
dfs(0, x, disx); int y = tmp;
dfs(0, y, disy);
int z, sum = 0;
for (int i = 1; i<=n; ++i)
if (sum<disx[y]+disx[i]+disy[i] && i!=x && i!=y) {
z = i;
sum = disx[y]+disx[i]+disy[i];
}
printf("%d\n%d %d %d\n", sum/2, x, y, z);
return 0;
}
Codeforces 1294F Three Paths on a Tree(树的直径)
原文:https://www.cnblogs.com/shuitiangong/p/12803043.html