构造完全图

https://loj.ac/problem/10067

题目描述

  给出一棵最小生成树,求有且仅有这一棵最小生成树的总边权最小的完全图。

思路

  我们考虑对于最小生成树中的一条边,它一定连接着两个连通支(T1,T2),并且是连通(T1、T2)的边中边权最小的,而我们构造完全图时,一定要将(T1、T2)中的节点两两连边,而显然除了最小生成树中的边(设其边权为(v))其余边权均为(v+1)时边权最小。所以我们可以记录每个连通支中的节点数,进行一次(Kruskal),在合并两个连通支时统计答案即可。

代码

#include <bits/stdc++.h>
using namespace std;
const int MAXN=1e5+10;
struct Edge
{
    int x,y,d;
}e[MAXN];
int fa[MAXN],siz[MAXN];
int find(int x)
{
    return fa[x]==x?x:fa[x]=find(fa[x]);
}
bool cmp(Edge x,Edge y)
{
    return x.d<y.d;
}
int main() 
{
    int n;
    scanf("%d",&n);
    for(int i=1;i<n;i++)
        scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].d);
    for(int i=1;i<=n;i++)
        fa[i]=i,siz[i]=1;
    sort(e+1,e+n,cmp);
    long long sum=0;
    int cnt=0;
    for(int i=1;i<n;i++)
    {
        int fx=find(e[i].x),fy=find(e[i].y);
        if(fx!=fy)
        {
            fa[fx]=fy;
            sum+=(long long)(siz[fx]*siz[fy]-1)*(e[i].d+1);
            sum+=e[i].d;
            siz[fy]+=siz[fx];
            cnt++;
            if(cnt==n-1)break ;
        }
    }
    printf("%lld",sum);
    return 0;
}
原文地址:https://www.cnblogs.com/fangbozhen/p/11794812.html