【CH6201】走廊潑水節
阿新 • • 發佈:2018-11-26
克魯斯卡爾算法 連接 bool \n == amp 算法 重新 mes
題目大意:給定一棵樹,要求增加若幹條邊,將其轉化為完全圖,且該完全圖以該樹為唯一的最小生成樹,求增加的邊權最小是多少。
題解:完全圖的問題一般要考慮組合計數。重新跑一遍克魯斯卡爾算法,每次並查集在合並時進行計數,因為要求最小生成樹唯一,必須保證每條邊都比當前連接兩個聯通塊的邊要至少大 1,因此每次合並對答案的貢獻為 \((w+1)*(size[x]*size[y]-1)\)。
代碼如下
#include <bits/stdc++.h> using namespace std; const int maxn=6010; struct node{ int from,to,w; bool operator<(const node& y)const{ return this->w<y.w; } }e[maxn]; int n,f[maxn],size[maxn]; long long ans; int find(int x){ return x==f[x]?x:f[x]=find(f[x]); } void read_and_parse(){ scanf("%d",&n); for(int i=1;i<n;i++)scanf("%d%d%d",&e[i].from,&e[i].to,&e[i].w); for(int i=1;i<=n;i++)f[i]=i,size[i]=1; } void solve(){ sort(e+1,e+n); for(int i=1;i<n;i++){ int x=find(e[i].from),y=find(e[i].to),z=e[i].w; ans+=(long long)(size[x]*size[y]-1)*(z+1); f[x]=y,size[y]+=size[x]; } printf("%lld\n",ans); } int main(){ int T;scanf("%d",&T); while(T--){ ans=0; read_and_parse(); solve(); } return 0; }
【CH6201】走廊潑水節