克魯斯卡爾最小生成樹演算法 - C++ 中的貪心演算法


生成樹是一個連線所有頂點的連通且無向的圖子圖。一個圖中可以存在許多生成樹。每個圖上的最小生成樹(MST)的權重都等於或小於所有其他生成樹。權重被分配到生成樹的邊上,並且總權重是每個邊分配權重的總和。由於 V 是圖中頂點的數量,因此最小生成樹具有 (V - 1) 條邊,其中 V 是邊的數量。

使用克魯斯卡爾演算法尋找最小生成樹

  • 所有邊都應按權重非降序排列。

  • 選擇最小的邊。如果不會形成環,則包含這條邊。

  • 重複步驟 2,直到生成樹具有 (V-1) 條邊。

在這種情況下,我們被告知要使用貪心方法。貪心選擇是選擇權重最小的邊。例如:此圖的最小生成樹為 (9-1)= 8 條邊。

After sorting:

Weight  Src    Dest
21       27    26
22       28    22
22       26    25
24       20    21
24       22    25
26       28    26
27       22    23
27       27    28
28       20    27
28       21    22
29       23    24
30       25    24
31       21    27
34       23    25

現在我們需要根據排序結果選擇所有邊。

邊 26-27 -> 包含,因為沒有形成環

邊 28-22 -> 包含,因為沒有形成環

邊 26-25 -> 包含,因為沒有形成環。

邊 20-21 -> 包含,因為沒有形成環

邊 22-25 -> 包含,因為沒有形成環。

邊 28-26 -> 丟棄,因為形成了環

邊 22-23 -> 包含,因為沒有形成環

邊 27-28 -> 丟棄,因為形成了環

邊 20-27 -> 包含,因為沒有形成環

邊 21-22 -> 丟棄,因為形成了環

邊 23-24 -> 包含,因為沒有形成環

由於邊的數量為 (V-1),因此演算法在此結束。

示例

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct Edge {
   int src, dest, weight;
};
struct Graph {
   int V, E;
   struct Edge* edge;
};
struct Graph* createGraph(int V, int E){
   struct Graph* graph = (struct Graph*)(malloc(sizeof(struct Graph)));
   graph->V = V;
   graph->E = E;
   graph->edge = (struct Edge*)malloc(sizeof( struct Edge)*E);
   return graph;
}
struct subset {
   int parent;
   int rank;
};
int find(struct subset subsets[], int i){
   if (subsets[i].parent != i)
      subsets[i].parent
   = find(subsets, subsets[i].parent);
   return subsets[i].parent;
}
void Union(struct subset subsets[], int x, int y){
   int xroot = find(subsets, x);
   int yroot = find(subsets, y);
   if (subsets[xroot].rank < subsets[yroot].rank)
      subsets[xroot].parent = yroot;
   else if (subsets[xroot].rank > subsets[yroot].rank)
      subsets[yroot].parent = xroot;
   else{
      subsets[yroot].parent = xroot;
      subsets[xroot].rank++;
   }
}
int myComp(const void* a, const void* b){
   struct Edge* a1 = (struct Edge*)a;
   struct Edge* b1 = (struct Edge*)b;
   return a1->weight > b1->weight;
}
void KruskalMST(struct Graph* graph){
   int V = graph->V;
   struct Edge
   result[V];
   int e = 0;
   int i = 0;
   qsort(graph->edge, graph->E, sizeof(graph->edge[0]), myComp);
   struct subset* subsets
   = (struct subset*)malloc(V * sizeof(struct subset));
   for (int v = 0; v < V; ++v) {
      subsets[v].parent = v;
      subsets[v].rank = 0;
   }
   while (e < V - 1 && i < graph->E) {
      struct Edge next_edge = graph->edge[i++];
      int x = find(subsets, next_edge.src);
      int y = find(subsets, next_edge.dest);
      if (x != y) {
         result[e++] = next_edge;
         Union(subsets, x, y);
      }
   }
   printf("Following are the edges in the constructed MST\n");
   int minimumCost = 0;
   for (i = 0; i < e; ++i){
      printf("%d -- %d == %d\n", result[i].src,
      result[i].dest, result[i].weight);
      minimumCost += result[i].weight;
   }
   printf("Minimum Cost Spanning tree : %d",minimumCost);
   return;
}
int main(){
   /* Let us create the following weighted graph
   30
   0--------1
   | \       |
   26| 25\ |15
   | \ |
   22--------23
   24 */
   int V = 24;
   int E = 25;
   struct Graph* graph = createGraph(V, E);
   graph->edge[0].src = 20;
   graph->edge[0].dest = 21;
   graph->edge[0].weight = 30;
   graph->edge[1].src = 20;
   graph->edge[1].dest = 22;
   graph->edge[1].weight = 26;
   graph->edge[2].src = 20;
   graph->edge[2].dest = 23;
   graph->edge[2].weight = 25;
   graph->edge[3].src = 21;
   graph->edge[3].dest = 23;
   graph->edge[3].weight = 35;
   graph->edge[4].src = 22;
   graph->edge[4].dest = 23;
   graph->edge[4].weight = 24;
   KruskalMST(graph);
   return 0;
}

輸出

Following are the edges in the constructed MST
22 -- 23 == 24
20 -- 23 == 25
20 -- 21 == 30
Minimum Cost Spanning tree : 79

結論

本教程演示瞭如何使用克魯斯卡爾最小生成樹演算法 - 貪心方法和 C++ 程式碼來解決此問題。我們也可以用 Java、Python 和其他語言編寫此程式碼。它以克魯斯卡爾的理念為模型。此程式在給定圖中找到最短的生成樹。希望本教程對您有所幫助。

更新於: 2022-03-07

3K+ 瀏覽量

開啟你的 職業生涯

透過完成課程獲得認證

開始學習
廣告

© . All rights reserved.