给定一个 n 个节点的树。
节点编号为 1∼n。
树中所有边均为双向边,且长度均已知。
你需要从 1 号点出发,沿着一条路径遍历树中所有点,路径中可以包含重复的点和边。
要求,你的行程总长度应尽可能短。
请你计算,你所需的行程总长度的最小可能值。
注意,你可以在任意点结束你的行程。
输入格式
第一行包含整数 n。
接下来 n−1 行,每行包含三个整数 x,y,w,表示点 x 和点 y 之间存在一条双向边,长度为 w。
输出格式
一个整数,表示行程总长度的最小可能值。
数据范围
前 4 个测试点满足 1≤n≤5。
所有测试点满足 1≤n≤10^5,1≤x,y≤n,0≤w≤2×10^4。
输入样例1:
3
1 2 3
2 3 4
输出样例1:
7
输入样例2:
3
1 2 3
1 3 3
输出样例2:
9
思路:经分析,要遍历整个树,除了起点到终点的边只用遍历一次,其余边都需要遍历两次。
所以答案res=sum*2-max;
要想res尽量小,max需足够大,所以遍历一遍整个树,求出最长的路径长度。
代码
#include<iostream>
#include<cstring>
using namespace std;
typedef long long LL;
const int N = 1e5 + 10, M = N * 2;
int e[M],w[M],ne[M],h[N],idx;
void add(int a,int b,int c)
{
e[idx]=b,w[idx]=c,ne[idx]=h[a],h[a]=idx++;
}
LL dfs(int a,int b)//作用:从起点到每一个最下边的子节点,找出最长路径
{
LL res=0;
for(int i=h[a];i!=-1;i=ne[i])
{
int j=e[i];
if(j==b) continue;//防止搜到父节点,然后无限循环
res=max(res,dfs(j,a)+w[i]);
}
return res;
}
int main()
{
memset(h,-1,sizeof h);
int n;
cin>>n;
LL sum=0;
for(int i=0;i<n-1;i++)
{
int a,b,c;
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
add(b,a,c);
sum+=c;
}
printf("%lld\n",sum*2-dfs(1,-1));//dfs(1,-1)从1搜到-1,也就是遍历整个树
return 0;
}