Codevs 2796 最小完全图

2796 最小完全图

http://codevs.cn/problem/2796/

题目描述 Description

若一个图的每一对不同顶点都恰有一条边相连,则称为完全图。

最小生成树MST在Smart的指引下找到了你,希望你能帮它变成一个最小完全图(边权之和最小的完全图)。

注意:必须保证这个最小生成树MST对于最后求出的最小完全图是唯一的。

输入描述 Input Description

第一行一个整数n,表示生成树的节点数。

接下来有n-1行,每行有三个正整数,依次表示每条边的顶点编号和边权。

(顶点的边号在1-n之间,边权<231)

输出描述 Output Description

一个整数ans,表示以该树为最小生成树的最小完全图的边权之和。

样例输入 Sample Input

4

1 2 1

1 3 1

1 4 2

样例输出 Sample Output

12

数据范围及提示 Data Size & Hint

30%的数据:n<1000;

100%的数据:n≤20000,所有的边权<2^31。

/*
树就是不存在环的图,而完全图就要求我们把树上的点间关系全部变成环 
首先把各边从小到大排序,以保证从小的开始,结果更优 
以树上的每条边为基底,进行合并
比如用到边i,其端点为a,b
将b所在的树合并到a所在的树上,也就是要求两棵小树中所有的点构成一个小的完全图 
那么从b树上所有点都向a图上所有点连一条长为v[i]+1的线即可,这样的线一共有siz[a]*siz[b]-1条 
上式中"-1"代表的那条边就是边i,其边权为v[i] 
就这样跑完最小生成树的所有边,同时将边权累加即可 
最后提醒 所有的边权<2^31,别忘了用long long 
*/
#include<iostream>
#include<cstdio>
#include<algorithm>
using namespace std;
long long siz[20010],n,ans,father[20010];
struct node{
    long long from,to,v;
}e[20010];
long long find(long long a){
    if(father[a]==a)return father[a];
    else return father[a]=find(father[a]);
}
long long cmp(node a,node b){
    return a.v<b.v;
}
int main(){
    scanf("%d",&n);
    for(long long i=1;i<n;i++)scanf("%d%d%d",&e[i].from,&e[i].to,&e[i].v);
    for(long long i=1;i<=n;i++)father[i]=i,siz[i]=1;
    sort(e+1,e+n,cmp);
    for(long long i=1;i<n;i++){
        long long a=e[i].from,b=e[i].to;
        long long f1=find(a),f2=find(b);
        father[f2]=f1;
        ans+=e[i].v;
        long long value=siz[f1]*siz[f2]-1;
        ans+=value*(e[i].v+1);
        siz[f1]+=siz[f2];//与19行对应,注意是谁变成了谁的子树 
    }
    cout<<ans;
}
原文地址:https://www.cnblogs.com/thmyl/p/6849818.html