最小完全圖
時間限制: 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\n",ans); return 0; }