题面
题解
我们要枚举每个点到其它点的最远距离,那么就会有两种情况,向上走或者是向下走
假设我们枚举u点,向下走 dfs_down(u) 更新当前节点向下走,叶子节点不需要更新
d1[u] 表示 u点向下的最长路径,d2[u] 表示 u 点向下的次长路径 ,p1[u] 表示 u 的向下最长路径经过的子节点 。 那么我们只要每次枚举u节点的儿子,然后更新即可
向上走:dfs_up 传入 u 节点, 我们更新它的每一个儿子(因为开始传入的u是根节点不需要向上更新)
对于u的儿子 j ,第一步肯定是向上走,距离是 w[i] , 那么接接下来就有两种方式,继续向上或向下 ,如果是从u节点向下的话,j是最长路径上的一个点,我们就选择次长的路径,如果j不是最长路径上的点,我们就选择最长路 ,然后向上,向下取一个最大即可
代码
#include<iostream>
#include<cstdio>
#include<string>
#include<cstring>
#include<algorithm>
using namespace std;
const int N = 1e4 + 10;
const int INF = 0x3f3f3f3f;
int n;
int h[N], e[N * 2], w[N * 2], ne[N * 2], idx;
int d1[N], d2[N], p1[N], up[N]; //p1数组标记这个节点的最长路径要经过哪个子节点
int is[N]; //标记是否为叶子节点
void add(int a, int b, int c) {
e[idx] = b;
w[idx] = c;
ne[idx] = h[a];
h[a] = idx++;
}
//向下求最长
int dfs_down(int u, int father) {
d1[u] = d2[u] = -INF;
for (int i = h[u]; i != -1; i = ne[i]) {
int j = e[i];
if (j == father) continue;
int d = dfs_down(j, u) + w[i]; //遍历求每个儿子的最长长度
if (d > d1[u]) d2[u] = d1[u], d1[u] = d, p1[u] = j; //更新这个节点的最长和次长
else if (d > d2[u]) d2[u] = d;
}
if (d1[u] == -INF) {
//说明是叶子节点
d1[u] = d2[u] = 0;
is[u] = true;
}
return d1[u];
}
//向上求最长
int dfs_up(int u, int father) {
for (int i = h[u]; i != -1; i = ne[i]) {
int j = e[i];
if (j == father) continue;
//u的最长经过点j,那么就要找次边
if (p1[u] == j) up[j] = max(up[u], d2[u]) + w[i];
else up[j] = max(up[u], d1[u]) + w[i];
dfs_up(j, u);
}
}
int main() {
memset(h, -1, sizeof h);
cin >> n;
for (int i = 1; i < n; i++) {
int a, b, c;
cin >> a >> b >> c;
add(a, b, c), add(b, a, c);
}
dfs_down(1, -1);
dfs_up(1, -1);
int res = d1[1];
for (int i = 2; i <= n; i++) {
if (is[i]) res = min(res, up[i]); //根节点只能向上找
else res = min(res, max(d1[i], up[i]));
}
cout << res << endl;
return 0;
}