思路:
求某个点使得它到图中的所有点的最大距离最小。
首先直接找图的直径是不对的,比如环上等距的三个点,然后其中一个点往外扩展了一个点,由于我求出来的点之后按理要放在直径的中点上,但这种情况显然不满足。
对于这种带了环的题目(又叫基环外向树),我们一般是断掉环上的某一条边,再作考虑。
把环上的某一条边断掉变成树再求直径就没问题了。
首先外送快餐店送餐的路径不会经过完整的一个环,所以断边对正确答案没有影响。因为环上的点有两个条路径,所以删掉不会导致“错过正确答案”。
先跑一遍dfs,找出环上的点编号(环上有top条边),以及点i和i+1的边的编号是i,点top和1的边编号top。
我们不知道断掉那条边最优,所以需要枚举断掉边
先断掉边top(环上边的编号,链接环上的第top个点和第1个点)
对环上每个点的子树跑一遍dfs得到dp[i]表示环上的第i个点子树的深度(同时求出所有子树内最大链长度)
然后求出表示环上的点的最大深度,last[i][0]表示经过环上的点中至少一个点的最大链长度
以及求出表示环上的点的最大深度,last[i][1]表示经过环上的点中至少一个点的最大链长度
断掉边top的最大链长度(需要经过环上的点)就是last[top][0];
断边i后的最大链(需要经过环上的点)可能是的最大链(需要经过环上的点),也可能是中深度最大的链相连(需要经过环上的点)。

长度最大的链可能不经过环上的点,所以最后还要和所有子树内最大链长度比较。

Code:

#include<bits/stdc++.h>
using namespace std;
typedef long long ll;
const int maxn=1e5+7,maxm=2e5+7;
int head[maxn],Next[maxm],to[maxm],fa[maxn],tot,b[maxn],top;
bool vis[maxn],sccno[maxn];
ll val[maxm],pre[maxn][2],last[maxn][2],fa_w[maxn],edge[maxn],dp[maxn],chain;
inline ll read() {
    ll s = 0, w = 1;
    char ch = getchar();
    while (ch < 48 || ch > 57) {
        if (ch == '-') w = -1;
        ch = getchar();
    }
    while (ch >= 48 && ch <= 57)
        s = (s << 1) + (s << 3) + (ch ^ 48), ch = getchar();
    return s * w;
}
void add(int x,int y,ll v) {
    to[++tot]=y;
    Next[tot]=head[x];
    head[x]=tot;
    val[tot]=v;
}
void dfs_find(int x,int f) {
    vis[x]=true;
    for(int i=head[x],y;i;i=Next[i]) {
        y=to[i];
        if(y==f||sccno[y]) continue;
        if(vis[y]) {
            int u=x;
            while(u!=y) {
                sccno[u]=true;
                b[++top]=u,edge[top]=fa_w[u];
                u=fa[u];
            }
            sccno[y]=true;
            b[++top]=y,edge[top]=val[i];
            continue;
        }
        fa[y]=x,fa_w[y]=val[i];
        dfs_find(y,x);
    }
}
void dfs(int x,int f) {
    for(int i=head[x],y;i;i=Next[i]) {
        y=to[i];
        if(y==f||sccno[y]) continue;
        dfs(y,x);
        chain=max(chain,dp[x]+dp[y]+val[i]);
        dp[x]=max(dp[x],dp[y]+val[i]);
    }
}
int main() {
    int n=read();
    for(int i=1,u,v,cost;i<=n;++i) {
        u=read(),v=read(),cost=read();
        add(u,v,cost);
        add(v,u,cost);
    }
    dfs_find(1,0);
    for(int i=1;i<=top;i++) dfs(b[i],0);
    ll sum=0,plus=0,duan=edge[top];
    for(int i=1,now;i<=top;++i) {
        sum+=edge[i-1];
        now=b[i];
        pre[i][0]=max(pre[i-1][0],dp[now]+sum);
        last[i][0]=max(last[i-1][0],dp[now]+plus+sum);
        plus=max(plus,dp[now]-sum);
    }
    edge[top]=sum=plus=0;
    for(int i=top,now;i;--i) {
        sum+=edge[i];
        now=b[i];
        pre[i][1]=max(pre[i+1][1],dp[now]+sum);
        last[i][1]=max(last[i+1][1],dp[now]+plus+sum);
        plus=max(plus,dp[now]-sum);
    }
    ll ans=last[top][0],choose=0;
    for(int i=1;i<top;++i) {
        choose=max(last[i][0],last[i+1][1]);
        choose=max(choose,pre[i][0]+pre[i+1][1]+duan);
        if(choose<ans) ans=choose;
    }
    ans=max(ans,chain);
    if(ans&1) printf("%lld.5",ans>>1);
    else printf("%lld.0",ans>>1);
    return 0;
}