题目描述
根据输入的顶点和边的相关信息构造一个带权的图也就是网,并应用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;
}