CF61D Eternal Victory 题解


题意

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

分析

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

代码

#include 
#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){}
};
vectoredge;
void add_edge(int u,int v,int w)
{
    edge.push_back(Edge{v,w,head[u]});
    head[u]=edge.size()-1;
}
priority_queue >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