树的中心
题目描述
给定一棵树,树中包含 n 个结点(编号1~n)和 n−1条无向边,每条边都有一个权值。
请你在树中找到一个点,使得该点到树中其他结点的最远距离最近。
输入格式
第一行包含整数 n。
接下来 n−1行,每行包含三个整数 ai,bi,ci,表示点 ai 和 bi之间存在一条权值为 ci 的边。
输出格式
输出一个整数,表示所求点到树中其他结点的最远距离。
数据范围
1≤n≤10000,
1≤ai,bi≤n,
1≤ci≤10^5
输入样例
5
2 1 1
3 2 1
4 3 1
5 1 1
输出样例
2
题目分析
代码实现
#include<iostream>
#include<cstring>
#include<algorithm>
using namespace std;
#define int long long
const int N=1e4+5,M=2*N,INF=0x3f3f3f3f;
int h[N],e[M],ne[M],w[M],idx;
int leaf[N],d1[N],d2[N],up[N],next1[N];
void add(int x,int y,int z){
e[idx]=y,w[idx]=z,ne[idx]=h[x],h[x]=idx++;
}
int dfs_down(int u,int f){
int dist=0;
d1[u]=d2[u]=0;
for(int i=h[u];~i;i=ne[i]){
int j=e[i];
//防止回头
if(j==f)continue;
//求当前结点向下的路径
int dis=dfs_down(j,u)+w[i];
//更新该结点向下的最长路径
dist=max(dist,dis);
//更新最长路径和次长路径
if(dis>d1[u])d2[u]=d1[u],d1[u]=dis,next1[u]=j;
else if(dis>d2[u])d2[u]=dis;
}
//如果该结点向下没有边,则说明该结点为叶子结点
if(dist==0)leaf[u]=1;
return dist;
}
void dfs_up(int u,int f){
for(int i=h[u];~i;i=ne[i]){
int j=e[i];
if(j==f)continue;
//如果u结点向下的最长路径经过了j,
//则表示j结点向上的最长路径为u的次长路径和u结点向上的最长路径的最大值加上w[i]
if(next1[u]==j)up[j]=max(up[u],d2[u])+w[i];
//否则则表示j结点向上的最长路径为u的最长路径和u结点向上的最长路径的最大值加上w[i]
else up[j]=max(up[u],d1[u])+w[i];
dfs_up(j,u);
}
}
signed main(){
int n,x,y,z;
cin>>n;
memset(h,-1,sizeof h);
for(int i=0;i<n-1;i++){
cin>>x>>y>>z;
//建立无向边
add(x,y,z);
add(y,x,z);
}
//更新向下的最长路径和次长路径长度
dfs_down(1,-1);
//更新向上的最长路径
dfs_up(1,-1);
int res=INF;
for(int i=1;i<=n;i++){
//如果该结点是叶子结点,则只需要比较向上的最长路径即可
if(leaf[i])res=min(res,up[i]);
//否则需要比较向上的最长路径和向下的最长路径
else res=min(res,max(up[i],d1[i]));
}
cout<<res<<endl;
return 0;
}