树的中心

题目描述

给定一棵树,树中包含 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

题目分析

image
image

代码实现

#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;
}
posted @ 2023-05-23 14:27  回忆、少年  阅读(26)  评论(0编辑  收藏  举报