1. 程式人生 > >最小完全圖

最小完全圖

限制 app left cnblogs 時間限制 output 依次 find col

時間限制: 1 s空間限制: 128000 KB題目等級 : 鉆石 Diamond

題目描述 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,所有的邊權<231

思路

題目意思為加邊至圖為完全圖之後,最小生成樹不變;

模擬克魯斯克萊算法流程;

點集合並時把未直連的邊用稍長的邊(+1)相連;

代碼實現

 1 #include<cstdio>
 2 #include<iostream>
 3 #include<algorithm>
 4 using namespace std;
 5 const int maxn=2e4+10;
 6 const int maxm=4e4+10;
 7 long long ans;
 8 int n;
 9 int a,b,c;
10 int h[maxn],hs;
11 struct edge{int s,t,w;}e[maxm];
12 int f[maxn],sz[maxn];
13
int find_f(int k){return f[k]==k?k:f[k]=find_f(f[k]);} 14 bool comp(const edge &x,const edge &y){return x.w<y.w;} 15 int main(){ 16 scanf("%d",&n); 17 for(int i=1;i<n;i++){ 18 scanf("%d%d%d",&a,&b,&c); 19 e[++hs]=(edge){a,b,c}; 20 ans+=c; 21 } 22 sort(e+1,e+hs+1,comp); 23 for(int i=1;i<=n;i++) f[i]=i,sz[i]=1; 24 for(int i=1;i<=hs;i++){ 25 a=find_f(e[i].s),b=find_f(e[i].t); 26 f[b]=a; 27 ans+=1ll*(1ll*sz[a]*sz[b]-1)*(e[i].w+1); 28 sz[a]+=sz[b]; 29 } 30 cout<<ans<<endl; 31 return 0; 32 }

最小完全圖