问题 A: Kruskal(克鲁斯卡尔)算法

题目描述

根据输入的顶点和边的相关信息构造一个带权的图也就是网,并应用Kruskal算法生成它的一棵最小生成树,设该生成树首个被访问的顶点为构造带权图时所输入的第一个顶点。若该图是连通的,则依次输出最小生成树的各条边的信息和权值和;否则输出ERROR。

输入

第一行为一个整数v(1≤v≤20),表示图的顶点个数;第二行有v个字符,分别表示v个顶点所显示的数据,各个顶点显示的数据互不相同;第三行为一个整数e(1≤e≤100),表示图的边的数量;接下来有e行,每行包括一个字符串(无空格,长度不超过30),分别表示图中某条边的起始顶点、终止顶点、边的权值。

输出

若该图是连通的,则依次输出最小生成树的各条边的信息,之后空一行再输出各条边的权值之和;否则输出ERROR。

样例输入

6 A B C D E F 10 A,B:6 A,C:1 A,D:5 B,C:5 B,E:3 C,D:5 C,E:6 C,F:4 D,F:2 E,F:6

样例输出

A,C:1 D,F:2 B,E:3 C,F:4 B,C:5 15

提示

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

#define MAX_VERTICES 20
#define MAX_EDGES 100

// 定义边的结构体
typedef struct {
    int start;
    int end;
    int weight;
} Edge;

// 定义图的结构体
typedef struct {
    int numVertices;
    char vertices[MAX_VERTICES];
    int numEdges;
    Edge edges[MAX_EDGES];
} Graph;

// 并查集的辅助函数,用于判断两个顶点是否在同一个集合中
int find(int parent[], int vertex) {
    if (parent[vertex] == -1)
        return vertex;
    return find(parent, parent[vertex]);
}

// 并查集的辅助函数,用于合并两个集合
void unionSet(int parent[], int x, int y) {
    int xSet = find(parent, x);
    int ySet = find(parent, y);
    parent[xSet] = ySet;
}

// 比较边的权值大小的比较函数,用于排序
int compare(const void* a, const void* b) {
    Edge* edgeA = (Edge*)a;
    Edge* edgeB = (Edge*)b;
    return edgeA->weight - edgeB->weight;
}

// Kruskal 算法生成最小生成树
void kruskal(Graph* graph) {
    Edge result[MAX_VERTICES];
    int parent[MAX_VERTICES];
    int i, e = 0, v = 0;

    // 初始化并查集
    memset(parent, -1, sizeof(parent));

    // 对边进行排序
    qsort(graph->edges, graph->numEdges, sizeof(Edge), compare);

    // 遍历所有边,选择最小的边加入最小生成树中
    for (i = 0; i < graph->numEdges && e < graph->numVertices - 1; ++i) {
        int startSet = find(parent, graph->edges[i].start);
        int endSet = find(parent, graph->edges[i].end);
        
        // 如果边的起始顶点和终止顶点不在同一个集合中,将该边加入最小生成树中
        if (startSet != endSet) {
            result[e++] = graph->edges[i];
            unionSet(parent, startSet, endSet);
        }
    }

    // 如果最小生成树的边数等于顶点数减一,说明生成树连通
    if (e == graph->numVertices - 1) {
        int sumWeight = 0;
  
        for (i = 0; i < e; ++i) {
            printf("%c,%c:%d\n", graph->vertices[result[i].start], graph->vertices[result[i].end], result[i].weight);
            sumWeight += result[i].weight;
        }
        printf("\n%d", sumWeight);
    } else {
        printf("ERROR");
    }
}

int main() {
    Graph graph;
    int i;

    // 读取顶点个数和顶点标识字符数组
    scanf("%d", &graph.numVertices);
    for (i = 0; i < graph.numVertices; ++i)
        scanf(" %c", &graph.vertices[i]);

    // 读取边的数量和边的信息
    scanf("%d", &graph.numEdges);
    for (i = 0; i < graph.numEdges; ++i) {
        char start, end;
        Edge edge;
        scanf(" %c,%c:%d", &start, &end, &edge.weight);
        edge.start = strchr(graph.vertices, start) - graph.vertices;
        edge.end = strchr(graph.vertices, end) - graph.vertices;
        graph.edges[i] = edge;
    }

    // 调用 Kruskal 算法生成最小生成树
    kruskal(&graph);

    return 0;
}
 

  • 31
    点赞
  • 35
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值