CH6201 走廊潑水節【最小生成樹】
6201 走廊潑水節 0x60「圖論」例題
描述
【簡化版題意】給定一棵N個節點的樹,要求增加若幹條邊,把這棵樹擴充為完全圖,並滿足圖的唯一最小生成樹仍然是這棵樹。求增加的邊的權值總和最小是多少。
我們一共有N個OIER打算參加這個潑水節,同時很湊巧的是正好有N個水龍頭(至於為什麽,我不解釋)。N個水龍頭之間正好有N-1條小道,並且每個水龍頭都可以經過小道到達其他水龍頭(這是一棵樹,你應該懂的..)。但是OIER門為了迎接中中的挑戰,決定修建一些個道路(至於怎麽修,秘密~),使得每個水龍頭到每個水龍頭之間都有一條直接的道路連接(也就是構成一個完全圖唄~)。但是OIER門很懶得,並且記性也不好,他們只會去走那N-1條小道,並且希望所有水龍頭之間修建的道路,都要大於兩個水龍頭之前連接的所有小道(小道當然要是最短的了)。所以神COW們,幫那些OIER們計算一下吧,修建的那些道路總長度最短是多少,畢竟修建道路是要破費的~~
輸入格式
本題為多組數據~
第一行t,表示有t組測試數據
對於每組數據
第一行N,表示水龍頭的個數(當然也是OIER的個數);
2到N行,每行三個整數X,Y,Z;表示水龍頭X和水龍頭Y有一條長度為Z的小道
輸出格式
對於每組數據,輸出一個整數,表示修建的所有道路總長度的最短值。
樣例輸入
2 3 1 2 2 1 3 3 4 1 2 3 2 3 4 3 4 5
樣例輸出
4 17
數據範圍與約定
- 每個測試點最多10組測試數據
50% n<=1500;
100% n<=6000
100% z<=100
樣例解釋
第一組數據,在2和3之間修建一條長度為4的道路,是這棵樹變成一個完全圖,且原來的樹依然是這個圖的唯一最小生成樹.
Contest Hunter - 信息學自助比賽平臺
題意:
題意題目第一段【簡化版題意】講得很清楚了,不重復了。
思路:
寫這道題首先要清楚最小生成樹kruskal算法的思想。
kruskal其實就是先將邊按權值排序,使用並查集,從小到大掃描邊,依次合並點的集合。
比如我們現在掃描到邊$e_i$,他的終點是$x$和$y$,他們分別屬於集合$S_x$集合$S_y$。
kruskal的過程就是把$S_x$和$S_y$合並,把$e_i$加入到答案中。
現在如果我們要添加邊使得他變成完全圖的話。那麽原來集合$S_x$和集合$S_y$應該只有$e_i$這一條邊可以使他們連通。
現在我們就要對每一對$u\epsilon S_x$, $v\epsilon S_y$添加一條邊,為了使$e_i$仍在最小生成樹中,添加的每條邊都應該大於$e_i$的權值$z$
又要使答案最小,所以應該添加權值為$z+1$的邊。添加的邊的條數應該是$size(S_x) * size(S_y) - 1$
1 #include<iostream> 2 //#include<bits/stdc++.h> 3 #include<cstdio> 4 #include<cmath> 5 #include<cstdlib> 6 #include<cstring> 7 #include<algorithm> 8 #include<queue> 9 #include<vector> 10 #include<set> 11 #include<climits> 12 #include<map> 13 using namespace std; 14 typedef long long LL; 15 #define N 100010 16 #define pi 3.1415926535 17 #define inf 0x3f3f3f3f 18 19 int t, n; 20 const int maxn = 6005; 21 int fa[maxn], cnt_son[maxn]; 22 struct edge{ 23 int u, v, w; 24 }e[maxn]; 25 bool cmp(edge a, edge b) 26 { 27 return a.w < b.w; 28 } 29 30 int get(int x) 31 { 32 if(x == fa[x])return x; 33 return fa[x] = get(fa[x]); 34 } 35 36 37 int main() 38 { 39 scanf("%d", &t); 40 while(t--){ 41 scanf("%d", &n); 42 for(int i = 0; i < n - 1; i++){ 43 scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w); 44 } 45 sort(e, e + n - 1, cmp); 46 for(int i = 1; i <= n; i++){ 47 fa[i] = i; 48 cnt_son[i] = 1; 49 } 50 51 int ans = 0; 52 for(int i = 0; i < n - 1; i++){ 53 int x = get(e[i].u); 54 int y = get(e[i].v); 55 if(x == y)continue; 56 ans += (e[i].w + 1) * (cnt_son[x] * cnt_son[y] - 1); 57 fa[x] = y; 58 cnt_son[x] = cnt_son[y] = cnt_son[x] + cnt_son[y]; 59 } 60 printf("%d\n", ans); 61 } 62 return 0; 63 }
CH6201 走廊潑水節【最小生成樹】