克魯斯卡爾演算法

2022-09-20 19:36:07 字數 3297 閱讀 2945

看乙個應用場景和問題:

某城市新增 7 個站點 (a, b, c, d, e, f, g) ,現在需要修路把 7 個站點連通

各個站點的距離用邊線表示 ( 權 ) ,比如 a – b 距離 12 公里

問:如何修路保證各個站點都能連通,並且總的修建公路總里程最短 ?

克魯斯卡爾 (kruskal) 演算法,是用來求加權連通圖的最小生成樹的演算法 。

基本思想 :按照權值從小到大的順序選擇 n-1 條邊,並保證這 n-1 條邊不構成迴路

具體做法 :首先構造乙個只含 n 個頂點的森林,然後依權值從小到大從連通網中選擇邊加入到森林中,並使森林中不產生迴路,直至森林變成一棵樹為止

克魯斯卡爾演算法**說明

以城市公交站問題來**說明 克魯斯卡爾演算法的原理和步驟:

在含有n個頂點的連通圖中選擇n-1條邊,構成一棵極小連通子圖,並使該連通子圖中n-1條邊上權值之和達到最小,則稱其為連通網的最小生成樹。

例如,對於如上圖g4所示的連通網可以有多棵權值總和不相同的生成樹。

以上圖g4為例,來對克魯斯卡爾進行演示(假設,用陣列r儲存最小生成樹結果)。

第1步:將邊加入r中。

邊的權值最小,因此將它加入到最小生成樹結果r中。

第2步:將邊加入r中。

上一步操作之後,邊的權值最小,因此將它加入到最小生成樹結果r中。

第3步:將邊加入r中。

上一步操作之後,邊的權值最小,因此將它加入到最小生成樹結果r中。

第4步:將邊加入r中。

上一步操作之後,邊的權值最小,但會和已有的邊構成迴路;因此,跳過邊。同理,跳過邊。將邊加入到最小生成樹結果r中。

第5步:將邊加入r中。

上一步操作之後,邊的權值最小,因此將它加入到最小生成樹結果r中。

第6步:將邊加入r中。

上一步操作之後,邊的權值最小,但會和已有的邊構成迴路;因此,跳過邊。同理,跳過邊。將邊加入到最小生成樹結果r中。

此時,最小生成樹構造完成!它包括的邊依次是:。

克魯斯卡爾演算法分析

根據前面介紹的克魯斯卡爾演算法的基本思想和做法,我們能夠了解到,克魯斯卡爾演算法重點需要解決的以下兩個問題:

問題一 對圖的所有邊按照權值大小進行排序。

問題二 將邊新增到最小生成樹中時,怎麼樣判斷是否形成了迴路。

問題一很好解決,採用排序演算法進行排序即可。

問題二,處理方式是:記錄頂點在"最小生成樹"中的終點,頂點的終點是"在最小生成樹中與它連通的最大頂點"。然後每次需要將一條邊新增到最小生存樹時,判斷該邊的兩個頂點的終點是否重合,重合的話則會構成迴路。

如何判斷是否構成迴路-舉例說明(如圖)

在將加入到最小生成樹r中之後,這幾條邊的頂點就都有了終點:

(01) c的終點是f。

(02) d的終點是f。

(03) e的終點是f。

(04) f的終點是f。

就是將所有頂點按照從小到大的順序排列好之後;某個頂點的終點就是"與它連通的最大頂點"。

因此,接下來,雖然是權值最小的邊。但是c和e的終點都是f,即它們的終點相同,因此,將加入最小生成樹的話,會形成迴路。這就是判斷迴路的方式。也就是說,我們加入的邊的兩個頂點不能都指向同乙個終點,否則將構成迴路。

public class kruskalcase ;

//克魯斯卡爾演算法的鄰接矩陣

int matrix = ,

/*b*/ ,

/*c*/ ,

/*d*/ ,

/*e*/ ,

/*f*/ ,

/*g*/ };

//大家可以在去測試其它的鄰接矩陣,結果都可以得到最小生成樹.

//建立kruskalcase 物件例項

kruskalcase kruskalcase = new kruskalcase(vertexs, matrix);

//輸出構建的

kruskalcase.print();

kruskalcase.kruskal();

}public kruskalcase(char vertexs, int matrix)

//初始化邊, 使用的是複製拷貝的方式

this.matrix = new int[vlen][vlen];

for(int i = 0; i < vlen; i++)

}//統計邊的條數

for(int i =0; i < vlen; i++) }}

}private void kruskal()

}//。

//統計並列印 "最小生成樹", 輸出 rets

system.out.println("最小生成樹為");

for(int i = 0; i < index; i++)

}/**

* 功能: 獲取下標為i的頂點的終點(), 用於後面判斷兩個頂點的終點是否相同

* @param ends : 陣列就是記錄了各個頂點對應的終點是哪個,ends 陣列是在遍歷過程中,逐步形成

//* @param i : 表示傳入的頂點對應的下標

* @return 返回的就是 下標為i的這個頂點對應的終點的下標, 一會回頭還有來理解

*/private int getend(int ends, int p1)

return p1;

}/**

** @param ch 頂點的值,比如'a','b'

* @return 返回ch頂點對應的下標,如果找不到,返回-1

*/private int getposition(char ch)

}//找不到,返回-1

return -1;

}/**

* 功能: 獲取圖中邊,放到edata 陣列中,後面我們需要遍歷該陣列

* 是通過matrix 鄰接矩陣來獲取

* edata 形式 [['a','b', 12], ['b','f',7], .....]

* @return

*/private edata getedges()

@override

public string tostring()

@override

public int compareto(edata o)

}

克魯斯卡爾演算法

測試輸入包含若干測試用例。每個測試用例的第1行給出評估的道路條數 n 村莊數目m 100 隨後的 n 行對應村莊間道路的成本,每行給出一對正整數,分別是兩個村莊的編號,以及此兩村莊間道路的成本 也是正整數 為簡單起見,村莊從1到m編號。當n為0時,全部輸入結束,相應的結果不要輸出。對每個測試用例,在...

克魯斯卡爾演算法

設n v,是連通網 1 令最小生成樹的初始狀態為只有n個頂點而無邊的非連通圖t v,圖中每個頂點自成乙個連通分量 2 在e中選擇代價最小的邊,若該邊依附的頂點落在t中不同的連通分量上,則將此邊加入到t中,否則捨去此邊而選擇下一條代價最小的邊 3 反覆執行第2 步,直至t中所有頂點都在同一連通分量上為...

克魯斯卡爾演算法

via 克魯斯卡爾演算法 在連通網中求出最小生成樹 include include define maxedge 20 define maxvex 20 define infinity 65535 typedef struct mgraph typedef struct edge 對邊集陣列edge...