藍書(演算法競賽進階指南)刷題記錄——CH6201 走廊潑水節(最小生成樹)
阿新 • • 發佈:2018-11-10
題目:CH6201.
題目大意:給定一棵樹,讓你擴充成一張完全圖,使得原樹是這張完全圖的唯一最小生成樹,並輸出加的邊的最小邊權和.
這道題用了一個類似於Kruskal的東西,然後順便計算出了最小邊權和.
首先,我們將樹拆開,將邊排序,然後不斷用並查集合並.
每合併一次,我們設合併的兩個聯通塊為x和y,那麼合併時就會x和y之間除了已有的這條邊本身,其它邊的邊權都要大於已有的這條邊.
而且我們可以發現,其它邊的限制條件肯定只有大於這條邊和比這條邊小的樹邊,所以我們發現其它邊的邊權只要設成這條邊的邊權+1即可.
那麼我們就kruskal的同時,每當加入一條邊,就將答案加上其它的邊的邊權,我們發現其它邊的數量即為x的大小乘上y的大小減1,邊權都為這條邊的邊權加1.寫成公式即為:
.
程式碼如下:
#include<bits/stdc++.h> using namespace std; #define Abigail inline void typedef long long LL; const int N=6000; struct side{ int x,y,v; bool operator < (const side p)const{return v<p.v;} }e[N+9]; int ans,n; int fa[N+9],cnt[N+9]; int get(int u){return fa[u]=u^fa[u]?get(fa[u]):u;} Abigail into(){ scanf("%d",&n); for (int i=1;i<n;i++) scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].v); } Abigail work(){ ans=0; for (int i=1;i<=n;i++) fa[i]=i,cnt[i]=1; stable_sort(e+1,e+n); for (int i=1;i<n;i++){ ans+=(e[i].v+1)*(cnt[get(e[i].x)]*cnt[get(e[i].y)]-1); cnt[get(e[i].x)]+=cnt[get(e[i].y)]; fa[get(e[i].y)]=get(e[i].x); } } Abigail outo(){ printf("%d\n",ans); } int main(){ int T; scanf("%d",&T); while (T--){ into(); work(); outo(); } return 0; }