Codevs 2796 最小完全图
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; }