Kruskal 演算法模板題

2021-08-04 20:32:12 字數 2619 閱讀 8107

描述

隨著小hi擁有城市數目的增加,在之間所使用的prim演算法已經無法繼續使用了——但是幸運的是,經過計算機的分析,小hi已經篩選出了一些比較適合建造道路的路線,這個數量並沒有特別的大。

所以問題變成了——小hi現在手上擁有n座城市,且已知其中一些城市間建造道路的費用,小hi希望知道,最少花費多少就可以使得任意兩座城市都可以通過所建造的道路互相到達(假設有a、b、c三座城市,只需要在ab之間和bc之間建造道路,那麼ac之間也是可以通過這兩條道路連通的)。

×close

小ho聽到了這個問題,發表了感慨:「這不就是之前最短路問題的時候針對點集變大,但是邊集很小的稀疏圖麼?和spfa演算法當時遇到的問題很像誒!」

小hi嚴肅道:「是的!在現實生活中,大部分的圖其實都是稀疏圖,哪怕不是,也可以像我這種通過篩選的方式轉化為稀疏圖!所以稀疏圖上的問題是非常重要的!」

「是的!」小ho連連稱是,繼續道:「那難道這題也像spfa那樣子來做麼?但是最小生成樹似乎是不可以用寬度優先搜尋來解決的啊?」

「倒也沒有那麼複雜。」小hi道:「還記的我們在prim演算法中得出的結論——對於城市i(i≠1),如果i與城市1的距離不超過其他任何城市j(j≠1)與城市1的距離,那麼(1, i)這一條邊一定存在於某一棵最小生成樹中麼?」

「自然記得。」

「我們來把這個結論稍微改一下:圖中最短的邊一定屬於某棵最小生成樹。」小hi說道:「證明是簡單的——因為城市1的標號是隨意的,也就是無論給哪個城市標1都會有之前的結論,那麼對於任意節點來說它連線的所有邊中最短的邊一定存在於某一棵最小生成樹中,而整個圖中最短的一條邊一定是這樣的一條邊。」

小ho道:「是的,那麼也就是說我只需要不斷的找到當前圖中最短的一條邊(一開始就將所有的邊排序然後從小到大)——這樣的一條邊一定屬於某棵最小生成樹!然後我只需要將連線的2個節點合併成為乙個新的節點,那麼這個問題就變成了乙個規模-1的問題了!只需要不斷重複這樣的操作,就能夠使得問題最後變成1的規模,這個時候只需要之前找到的所有一定存在於最小生成樹中的邊的費用加起來就是答案了就可以了!」

小hi點了點頭,說道:「那麼還剩乙個問題,在prim問題中,由於合併都是和1號城市合併,所以只需要簡單的記錄乙個節點是否已經合併進了1號城市就可以了,但是在這裡卻會複雜很多,你有什麼想法麼?」

「你這就太小看我的記憶力了!」小ho抱怨道:「在當年遇到黑叔叔的時候,我們不是學會了一種並查集的方法麼?在這裡只需要用並查集維護哪些節點被合併到了一起,不就行了?」

「嗯~ o(* ̄▽ ̄*)o,算你聰明,趕緊去實現程式吧!」

close

輸入每個測試點(輸入檔案)有且僅有一組測試資料。

在一組測試資料中:

第1行為2個整數n、m,表示小hi擁有的城市數量和小hi篩選出路線的條數。

接下來的m行,每行描述一條路線,其中第i行為3個整數n1_i, n2_i, v_i,分別表示這條路線的兩個端點和在這條路線上建造道路的費用。

對於100%的資料,滿足n<=10^5, m<=10^6,於任意i滿足1<=n1_i, n2_i<=n, n1_i≠n2_i, 1<=v_i<=10^3.

對於100%的資料,滿足一定存在一種方案,使得任意兩座城市都可以互相到達。

輸出對於每組測試資料,輸出1個整數ans,表示為了使任意兩座城市都可以通過所建造的道路互相到達至少需要的建造費用。

sample input

5 29

1 2 674

2 3 249

3 4 672

4 5 933

1 2 788

3 4 147

2 4 504

3 4 38

1 3 65

3 5 6

1 5 865

1 3 590

1 4 682

2 4 227

2 4 636

1 4 312

1 3 143

2 5 158

2 3 516

3 5 102

1 5 605

1 4 99

4 5 224

2 4 198

3 5 894

1 5 845

3 4 7

2 4 14

1 4 185

sample output

92
題意概括:有n個城市,m條路每條路都有不同的費用,最少需要花費多少才能使所有的城市連線在一起?

解題思路:簡單的kruskal模板。

**:#include#include#includeusing namespace std;

#define m 1100000

#define n 110000

struct edge

e[m];

int i,j,m,n;

int f[n];

bool cmp(edge a,edge b)

return s;

} void union(int u ,int v)

else

}

void kruskal()

{

int sum=0,num=0; uset();for(i=0;i

Kruskal演算法求最小生成樹(模板題)

題目鏈結 模板 模板來自acwing int n,m n是點數,m是邊數 int p n 並查集的父節點陣列 struct edge 儲存邊 edges m int find int x 並查集核心操作 int kruskal if cnt n 1 return inf return res 給定乙...

Kruskal演算法模板(C語言)

kruskal演算法是求連通網的最小生成樹的另一種方法,該演算法的思想是從小到大加入邊,是個貪心演算法,演算法的時間主要消耗在對邊進行排序,時間複雜度為o eloge 適合求邊數較少圖的最小生成樹。如下 include include include const int n 100010 typed...

最小生成樹Kruskal演算法模板

利用陣列fa來記錄各個節點的父節點,初始化為自己 通過sort排序,從邊長最短到最長 for 邊長 判斷 如果邊的兩個端點的父節點不相同,可選 把選過的邊的兩端點中,大序號的父節點處理為小序號的父節點 include include using namespace std define n 28 i...