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

Codevs 2796 最小完全圖

ret smart 端點 val cmp ble scanf sin else

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; }

Codevs 2796 最小完全圖