1. 程式人生 > >CH6201 走廊潑水節【最小生成樹】

CH6201 走廊潑水節【最小生成樹】

its ios main return 平臺 pan 最小生成樹 最小 algo

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 走廊潑水節【最小生成樹】