知识点:树的直径
解题思路
题目中“可以保证,任两个居住点间有且仅有一条通路”说明输入数据是一棵树。显然最优解需要从C先跑到A在跑到B.或者从C先跑到B在跑到A。
假设我们已经确定A,B点,那么AB是必走的,CA,CB会选取其中小的一段走,所以我们的C点要满足min(CA,CB)最大,这样就可以使答案最大。
如何确定A,B点?既然AB是必走的,那当然越长越好,所以就是树的直径了。由于这里只需要求树直径的端点和总长而不用求具体路线,我就选择了DFS来求。
简要介绍一下DFS求直径的方法:随意选取一个点,DFS出离它距离最大的点(设为P),再以P为起点,DFS出离它距离最大的点(设为Q),P,Q两点就是我们的A和B。
记得开long long
代码
#include<iostream>
#include<cstdio>
#include<iomanip>
#include<cstring>
#include<algorithm>
#include<cmath>
#include<queue>
#define ll long long
using namespace std;
int n,m,u,v,t,k=1,s,e,w,head[400010];
ll maxn,ans,fs[400010],fe[400010],f[400010],d[400010];
struct c {
int x,next;
ll w;
} a[400010];
void add(int x,int y,ll w) {
a[k].x=y;
a[k].next=head[x];
a[k].w=w;
head[x]=k;
k++;
}
void dfs(int x,int fa) {
if(maxn<d[x]) {
maxn=d[x];
w=x;
}
for(int i=head[x]; i; i=a[i].next) {
int y=a[i].x;
if(y!=fa) {
d[y]=d[x]+a[i].w;
dfs(y,x);
}
}
}
void dfs2(int x,int fa) {
for(int i=head[x]; i; i=a[i].next) {
int y=a[i].x;
if(y!=fa) {
f[y]=f[x]+a[i].w;
dfs2(y,x);
}
}
}
int main() {
scanf("%d%d",&n,&m);
for(int i=1; i<=m; i++) {
scanf("%d%d%lld",&u,&v,&t);
add(u,v,t);
add(v,u,t);
}
dfs(1,0);
s=w;
d[s]=0,maxn=0;
dfs(s,0);
e=w;
dfs2(s,0);
for(int i=1; i<=n; i++)
fs[i]=f[i];
f[e]=0;
dfs2(e,0);
for(int i=1; i<=n; i++)
fe[i]=f[i];
for(int i=1; i<=n; i++) {
if(i!=s&&i!=e)
ans=max(ans,min(fe[i],fs[i]));
}
printf("%lld",ans+maxn);
}