#include <stdio.h>
#include <stdlib.h>

#define MAX_VERTEX_NUM 100 //最大顶点数
#define MAX_EDGE_NUM 100 //最大边数

//边结构体
typedef struct {
    int tail; //边的起点
    int head; //边的终点
    int weight; //边的权值
} Edge;

//图结构体
typedef struct {
    int vertexNum; //顶点数
    int edgeNum; //边数
    Edge edges[MAX_EDGE_NUM]; //边数组
} Graph;

//并查集结构体
typedef struct {
    int parent[MAX_VERTEX_NUM]; //父节点数组
    int rank[MAX_VERTEX_NUM]; //秩数组
} UnionFindSet;

//初始化并查集
void MakeSet(UnionFindSet *set, int n) {
    for (int i = 0; i < n; i++) {
        set->parent[i] = i;
        set->rank[i] = 0;
    }
}

//查找节点所在集合的代表元
int Find(UnionFindSet *set, int x) {
    if (set->parent[x] != x) {
        set->parent[x] = Find(set, set->parent[x]);
    }
    return set->parent[x];
}

//合并两个集合
void Union(UnionFindSet *set, int x, int y) {
    int xRoot = Find(set, x);
    int yRoot = Find(set, y);
    if (xRoot == yRoot) {
        return;
    }
    if (set->rank[xRoot] < set->rank[yRoot]) {
        set->parent[xRoot] = yRoot;
    } else if (set->rank[xRoot] > set->rank[yRoot]) {
        set->parent[yRoot] = xRoot;
    } else {
        set->parent[yRoot] = xRoot;
        set->rank[xRoot]++;
    }
}

//边比较函数,用于排序
int cmp(const void *a, const void *b) {
    Edge *e1 = (Edge *)a;
    Edge *e2 = (Edge *)b;
    return e1->weight - e2->weight;
}

//破圈法求最小生成树
void Kruskal(Graph *graph) {
    //按权值从小到大排序
    qsort(graph->edges, graph->edgeNum, sizeof(Edge), cmp);
    //初始化并查集
    UnionFindSet set;
    MakeSet(&set, graph->vertexNum);
    //记录删除的边
    Edge removedEdges[MAX_EDGE_NUM];
    int removedEdgeNum = 0;
    //遍历所有边
    for (int i = 0; i < graph->edgeNum; i++) {
        Edge e = graph->edges[i];
        //如果边的两个端点不在同一个集合中,说明不会形成环,可以加入最小生成树中
        if (Find(&set, e.tail) != Find(&set, e.head)) {
            Union(&set, e.tail, e.head);
            printf('边 (%d, %d) 权值为 %d 加入最小生成树\n', e.tail, e.head, e.weight);
        } else {
            //否则,删除边
            removedEdges[removedEdgeNum++] = e;
        }
    }
    //输出删除的边
    printf('删除的边:\n');
    for (int i = 0; i < removedEdgeNum; i++) {
        Edge e = removedEdges[i];
        printf('(%d, %d) 权值为 %d\n', e.tail, e.head, e.weight);
    }
}

int main() {
    int n, m; //顶点数和边数
    Graph graph;
    printf('请输入顶点数和边数:');
    scanf('%d %d', &n, &m);
    graph.vertexNum = n;
    graph.edgeNum = m;
    printf('请输入每条边的起点、终点和权值:\n');
    for (int i = 0; i < m; i++) {
        Edge e;
        scanf('%d %d %d', &e.tail, &e.head, &e.weight);
        graph.edges[i] = e;
    }
    Kruskal(&graph);
    return 0;
}
C语言实现破圈法求解带权连通图的最小生成树

原文地址: https://www.cveoy.top/t/topic/fXqC 著作权归作者所有。请勿转载和采集!

免费AI点我,无需注册和登录