求树的直径,因为任意两个居住点之间有且只有一条通路,所以这是一棵树。
根据题意父母先从C去A,再去B,或者反过来。
我们一定是要让A到B最大,也要让C到A和B的最小值最大。
AB最大一定就是直径了。
CA最大直接先求出任意一条直径的两个端点,必定一个是A、一个是B。然后枚举C,找到最大的\(min(CA,CB)\)然后与AB相加即可。
#include <bits/stdc++.h> #define int long long #define N 1010011 using namespace std; struct edg { int from, to, nex, len;// vis表示是否在最大生成树上 }e[N * 2]; int n, m, cnt, ans, ansk, lin[N], dis1[N], vis[N];// 这必是一颗树 int disk[N]; inline void add(int f, int t, int c) { e[++cnt].nex = lin[f]; e[cnt].to = t; e[cnt].len = c; lin[f] = cnt; } void dfs(int now) { vis[now] = 1; for (int i = lin[now]; i; i = e[i].nex) { int to = e[i].to; if (!vis[to]) { dis1[to] = dis1[now] + e[i].len; ans = max(ans, dis1[to]); dfs(to); } } } void dfs2(int now) { vis[now] = 1; for (int i = lin[now]; i; i = e[i].nex) { int to = e[i].to; if (!vis[to]) { disk[to] = disk[now] + e[i].len; if (disk[to] > ans) ans = max(ans, disk[to]), ansk = to; dfs2(to); } } } signed main() { scanf("%lld%lld", &n, &m); for (int i = 1, a, b, c; i <= m; i++) { scanf("%lld%lld%lld", &a, &b, &c); add(a, b, c); add(b, a, c); } dfs(1); int maxn = 0, maxk = 0; for (int i = 2; i <= n; i++) { if (dis1[i] > maxn) { maxn = dis1[i]; maxk = i; } } ans = 0; maxn = 0; memset(vis, 0, sizeof(vis)); dfs2(maxk); memset(vis, 0, sizeof(vis)); memset(dis1, 0, sizeof(dis1)); dfs(ansk); for (int i = 1; i <= n; i++) { if (i == maxk || i == ansk) continue; maxn = max(maxn, min(dis1[i], disk[i])); } printf("%lld", maxn + ans);//ans是树的直径大小。 } /* 4 3 1 2 1 1 3 1 1 4 2 5 */