图论 —— 生成树 —— 最小生成树 —— Kruskal
【基本思想】
Kruskal 算法基本思想是并查集思想,將所有邊升序排序,并認為每一個點都是孤立的,分屬 n 個獨立的集合。
按順序枚舉每一條邊,如果這條邊連接的兩個點分屬兩個不同的集合,那么就將這條邊加入最小生成樹,這兩個不同的集合合并為一個集合;如果這條邊連接的兩個點屬于同一集合,那么就跳過。直到選取 n-1條邊為止(只剩一個集合)。
其時間復雜度為:O(E*logE),E代表邊數。
【算法分析】
以下圖為例
開始時,5 個集合{{1},{2},{3},{4},{5}},生成樹中沒有邊,MST=0。
第一次選擇 <1,2> 這條邊,將邊加入生成樹中,將兩個頂點 1、2 合并為一個集合。
此時,有 4 個集合{{1,2},{3},{4},{5}},1 條邊{<1,2>},MST=2。
第二次選擇的是 <4,5> 這條邊,將這條邊加入生成樹中,將兩個頂點 4、5 合并為一個集合。
此時,有 3 個集合{{1,2},{3},{4,5}},2 條邊{<1,2>,<4,5>},MST=5。
第三次選擇的是 <3,5> 這條邊,將這條邊加入生成樹中,將它的兩個頂點 3、5 所在的兩個集合合并為一個集合。
此時,有 2 個集合{{1,2},{3,4,5}},3 條邊{<1,2>,<4,5>,<3,5>},MST=11。
第四次選擇的是 <2,5> 這條邊,將這條邊加入到生成樹中,將它的兩個頂點 2、5 所在的兩個集合合并為一個集合。
此時,有 1 個集合{1,2,3,4,5},4 條邊{<1,2>,<4,5>,<3,5>,<2,5>},MST=19。
【算法描述】
struct Edge {int x, y;int dis;bool operator<(Edge K) const { return dis < K.dis; } } edge[N]; int father[N]; int Find(int x) {if (father[x] == x)return x;return father[x] = Find(father[x]); } int kruskal(int n, int m) {for (int i = 1; i <= n; i++) //并查集初始化father[i] = i;sort(edge + 1, edge + m + 1); //升序排序int MST = 0;int edgeNum = 0; //邊數for (int i = 1; i <= m; i++) {int x = Find(edge[i].x);int y = Find(edge[i].y);if (x != y) {father[x] = y;MST += edge[i].dis;edgeNum++;}if (edgeNum == n - 1) { // n-1條邊時停止return MST;}} } int main() {int n, m;scanf("%d%d", &n, &m);for (int i = 1; i <= m; ++i)scanf("%d%d%d", &edge[i].x, &edge[i].y, &edge[i].dis);int MST = kruskal(n, m);printf("%d\n", MST);return 0; }總結
以上是生活随笔為你收集整理的图论 —— 生成树 —— 最小生成树 —— Kruskal的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 数列极差(信息学奥赛一本通-T1427)
- 下一篇: 基础算法 —— 调度问题