CF61D Eternal Victory 题解

题意

求从 \(1\) 号节点开始,遍历一个 \(n\) 个点, \(n-1\) 条边的无向图所需要的最短距离。

分析

因为这个无向图由 \(n\) 个点, \(n-1\) 条边组成,所以这个图一定是一棵树。如图,我们可以发现,遍历一棵树,肯定会将一条链经过一次,其余的每条边都会被经过两次,为了使总距离最小,就让只经过一次的那条链最长即可。由于在树上两点之间不走回头路的路径唯一,因此可以以 \(1\) 号节点为起始点,在整张图上跑最短路,对每一条最短路的长度取最大值,就能得到最长链。最终答案就是所有边权和的 \(2\) 倍减最长链的长度。

代码

#include <bits/stdc++.h>
#define mem(a,b) memset(a,b,sizeof(a));
#define int long long
using namespace std;
const int MAXN=1e5+7;
int n;
int head[MAXN];
struct Edge
{
    int to,dis,nxt;
    Edge(){;}
    Edge(int _to,int _dis,int _nxt):to(_to),dis(_dis),nxt(_nxt){}
};
vector<Edge>edge;
void add_edge(int u,int v,int w)
{
    edge.push_back(Edge{v,w,head[u]});
    head[u]=edge.size()-1;
}
priority_queue<pair<int,int> >q;
int dis[MAXN];
bool vis[MAXN];
void dijkstra(int s)
{
    mem(dis,0x7f);mem(vis,0);
    dis[s]=0;
    q.push(make_pair(0,s));
    while(!q.empty())
    {
        int u=q.top().second;
        q.pop();
        if(vis[u]) continue;
        vis[u]=true;
        for(int i=head[u];i!=-1;i=edge[i].nxt)
        {
            if(dis[edge[i].to]>dis[u]+edge[i].dis)
            {
                dis[edge[i].to]=dis[u]+edge[i].dis;
                q.push(make_pair(-dis[edge[i].to],edge[i].to));
            }
        }
    }
}
signed main()
{
    scanf("%lld",&n);
    mem(head,-1);
    int i,j,sum=0;
    for(i=0;i<n-1;i++) 
    {
        int u,v,w;
        scanf("%d%d%d",&u,&v,&w);sum+=w*2;
        add_edge(u,v,w);
        add_edge(v,u,w);
    }
    dijkstra(1);int mx=0;
    for(i=1;i<=n;i++) mx=max(mx,dis[i]); 
    printf("%lld\n",sum-mx);
    // system("pause");
    return 0;
}
posted @ 2022-02-18 11:03  l_x_y  阅读(35)  评论(0编辑  收藏  举报