看乙個應用場景和問題:
某城市新增 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...