最小完全图
时间限制: 1 s
空间限制: 128000 KB
题目描述 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。
题目链接:http://codevs.cn/problem/2796/
分析Kruskal算法可知,最小生成树中的每一条边,都是连接某两个连通块的所有边中,最小的那一个。因此我们要造一个完全图,连接这两个连通块的所有边都必须大于最小生成树中对应的边。
所以对最小生成数中的边按升序排列,依次维护加边操作和对应连通块中点的个数就行了。
#include<bits/stdc++.h> #define N 20050 using namespace std; long long pre[N]; long long num[N]={0}; void init() { for(long long i=0;i<N;i++)pre[i]=i,num[i]=1; } long long Find(long long x) { long long boss=x; while(pre[boss]!=boss)boss=pre[boss]; while(x!=boss) { long long now=pre[x]; pre[x]=boss; x=now; } return boss; } struct ss { long long u,v,w; bool operator < (const ss&s) const { return w<s.w; } }; ss edge[N]; int main() { long long n; init(); scanf("%lld",&n); for(long long i=1;i<n;i++) { scanf("%lld %lld %lld",&edge[i].u,&edge[i].v,&edge[i].w); } sort(edge+1,edge+n); long long ans=0; for(long long i=1;i<n;i++) { long long u=edge[i].u,v=edge[i].v; ans+=(edge[i].w+1)*(num[Find(u)]*num[Find(v)]-1); ans+=edge[i].w; num[Find(v)]+=num[Find(u)]; pre[Find(u)]=Find(v); } printf("%lld ",ans); return 0; }