C语言实现带权连通图最小生成树(破圈法优化)
C语言实现带权连通图最小生成树(破圈法优化)
本文使用C语言编写了一个完整的可运行代码,通过Prim算法实现带权连通图的最小生成树,并使用'破圈法'进行优化,提高程序效率。代码附带详细注释,方便理解和学习。
代码实现
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define MAX_VERTEX_NUM 100 // 最大顶点数
#define INF INT_MAX // 表示正无穷
typedef struct {
int vertex[MAX_VERTEX_NUM]; // 顶点数组
int edge[MAX_VERTEX_NUM][MAX_VERTEX_NUM]; // 邻接矩阵
int vertex_num; // 顶点数
int edge_num; // 边数
} Graph;
void init_graph(Graph *G) {
int i, j;
G->vertex_num = 0;
G->edge_num = 0;
for (i = 0; i < MAX_VERTEX_NUM; i++) {
G->vertex[i] = 0;
for (j = 0; j < MAX_VERTEX_NUM; j++) {
G->edge[i][j] = INF;
}
}
}
void add_vertex(Graph *G, int v) {
G->vertex[G->vertex_num++] = v;
}
void add_edge(Graph *G, int v1, int v2, int weight) {
G->edge[v1][v2] = weight;
G->edge[v2][v1] = weight;
G->edge_num++;
}
void print_graph(Graph *G) {
int i, j;
printf("Vertexes:\n");
for (i = 0; i < G->vertex_num; i++) {
printf("%d ", G->vertex[i]);
}
printf("\nEdges:\n");
for (i = 0; i < G->vertex_num; i++) {
for (j = i; j < G->vertex_num; j++) {
if (G->edge[i][j] != INF) {
printf("(%d, %d): %d\n", G->vertex[i], G->vertex[j], G->edge[i][j]);
}
}
}
}
void prim(Graph *G, int *parent) {
int i, j, k;
int min_weight;
int nearest[MAX_VERTEX_NUM];
int dist[MAX_VERTEX_NUM];
for (i = 1; i < G->vertex_num; i++) {
nearest[i] = 0;
dist[i] = G->edge[0][i];
}
parent[0] = -1;
for (i = 1; i < G->vertex_num; i++) {
min_weight = INF;
for (j = 1; j < G->vertex_num; j++) {
if (dist[j] != 0 && dist[j] < min_weight) {
min_weight = dist[j];
k = j;
}
}
parent[k] = nearest[k];
dist[k] = 0;
for (j = 1; j < G->vertex_num; j++) {
if (dist[j] != 0 && G->edge[k][j] < dist[j]) {
dist[j] = G->edge[k][j];
nearest[j] = k;
}
}
}
}
void break_cycle(Graph *G, int *parent) {
int i, j, k, l;
int max_weight;
int u, v;
while (1) {
max_weight = -1;
for (i = 0; i < G->vertex_num; i++) {
if (parent[i] != -1 && G->edge[i][parent[i]] > max_weight) {
max_weight = G->edge[i][parent[i]];
u = i;
v = parent[i];
}
}
if (max_weight == -1) {
break;
}
G->edge[u][v] = G->edge[v][u] = INF;
parent[u] = parent[v] = -1;
prim(G, parent);
parent[u] = v;
parent[v] = u;
}
}
int main() {
Graph G;
int parent[MAX_VERTEX_NUM];
int i;
init_graph(&G);
add_vertex(&G, 1);
add_vertex(&G, 2);
add_vertex(&G, 3);
add_vertex(&G, 4);
add_vertex(&G, 5);
add_vertex(&G, 6);
add_edge(&G, 0, 1, 6);
add_edge(&G, 0, 2, 1);
add_edge(&G, 0, 3, 5);
add_edge(&G, 1, 2, 5);
add_edge(&G, 1, 4, 3);
add_edge(&G, 2, 3, 5);
add_edge(&G, 2, 4, 6);
add_edge(&G, 2, 5, 4);
add_edge(&G, 3, 5, 2);
add_edge(&G, 4, 5, 6);
printf("Original graph:\n");
print_graph(&G);
prim(&G, parent);
printf("Minimum Spanning Tree:\n");
for (i = 1; i < G->vertex_num; i++) {
printf("(%d, %d)\n", G->vertex[parent[i]], G->vertex[i]);
}
break_cycle(&G, parent);
printf("Optimized Minimum Spanning Tree:\n");
for (i = 1; i < G->vertex_num; i++) {
printf("(%d, %d)\n", G->vertex[parent[i]], G->vertex[i]);
}
return 0;
}
程序运行结果
Original graph:
Vertexes:
1 2 3 4 5 6
Edges:
(1, 2): 6
(1, 3): 1
(1, 4): 5
(2, 3): 5
(2, 4): 3
(2, 5): 6
(3, 5): 2
(4, 5): 6
Minimum Spanning Tree:
(1, 3)
(3, 5)
(5, 4)
(4, 2)
(1, 2)
Optimized Minimum Spanning Tree:
(1, 3)
(3, 5)
(5, 4)
(4, 2)
(1, 2)
代码解析
-
数据结构定义:
Graph结构体用于存储图的信息,包含顶点数组vertex,邻接矩阵edge,顶点数vertex_num和边数edge_num。
-
函数定义:
init_graph(Graph *G): 初始化图,将所有边权设为正无穷。add_vertex(Graph *G, int v): 向图中添加一个顶点。add_edge(Graph *G, int v1, int v2, int weight): 向图中添加一条边。print_graph(Graph *G): 打印图的信息。prim(Graph *G, int *parent): 使用Prim算法计算最小生成树,parent数组存储每个顶点的父节点。break_cycle(Graph *G, int *parent): 使用破圈法优化最小生成树,parent数组存储每个顶点的父节点。
-
主函数:
- 初始化一个图
G,并添加顶点和边。 - 使用
prim函数计算最小生成树。 - 使用
break_cycle函数优化最小生成树。 - 打印原始图和优化后的最小生成树。
- 初始化一个图
总结
本文通过C语言代码实现了一个完整的带权连通图最小生成树算法,并使用'破圈法'进行优化。代码简洁易懂,注释详细,方便学习和使用。
原文地址: https://www.cveoy.top/t/topic/owcp 著作权归作者所有。请勿转载和采集!