克鲁斯卡尔最小生成树算法 - 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 和其他语言编写此代码。它以克鲁斯卡尔的理念为模型。此程序在给定图中找到最短的生成树。希望本教程对您有所帮助。
广告