最小生成树问题
题目详情如下:
从文件中读取一个交通网络图,图中包含若干城市间的距离信息,设计程序,分别以每个城市为起点,建立最小生成树并输出,并计算得到的最小生成树的代价。要求:
(1)交通图自己设计,至少要包含20个城市,40条边,城
市用实际的城市命名。
(2)以邻接矩阵为存储结构分别用prim算法和kruskal算法
实现上述操作。
(3)以邻接表为存储结构分别用prim算法和kruskal算法实
现上述操作。
(4)最小生成树的输出格式为:
第1条边 郑州——>武汉 500公里
第2条边 武汉——>长沙 630公里
……
以邻接矩阵为存储结构的Prim算法
我的代码:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include<bits/stdc++.h>
#define INF 999999
#define MAX 20
typedef struct {
char city[MAX][20];
int distance[MAX][MAX];
int cityCount;
} Graph;
int readGraph(Graph *g, const char *filename) {
FILE *file = fopen(filename, "r");
if (!file) {
printf("无法打开文件\n");
return 0;
}
g->cityCount = 0;
for (int i = 0; i < MAX; i++) {
for (int j = 0; j < MAX; j++) {
g->distance[i][j] = INF;
}
}
char city1[20], city2[20];
int dist;
while (fscanf(file, "%s %s %d", city1, city2, &dist) == 3) {
int index1 = -1, index2 = -1;
for (int i = 0; i < g->cityCount; i++) {
if (strcmp(g->city[i], city1) == 0) {
index1 = i;
}
if (strcmp(g->city[i], city2) == 0) {
index2 = i;
}
}
if (index1 == -1) {
strcpy(g->city[g->cityCount], city1);
index1 = g->cityCount++;
}
if (index2 == -1) {
strcpy(g->city[g->cityCount], city2);
index2 = g->cityCount++;
}
g->distance[index1][index2] = dist;
g->distance[index2][index1] = dist;
}
fclose(file);
return 1;
}
void prim(Graph *g, int start) {
int cost[MAX], visited[MAX], parent[MAX];
for (int i = 0; i < g->cityCount; i++) {
cost[i] = INF;
visited[i] = 0;
parent[i] = -1;
}
cost[start] = 0;
for (int i = 0; i < g->cityCount - 1; i++) {
int minCost = INF, u = -1;
for (int j = 0; j < g->cityCount; j++) {
if (!visited[j] && cost[j] < minCost) {
minCost = cost[j];
u = j;
}
}
visited[u] = 1;
for (int v = 0; v < g->cityCount; v++) {
if (!visited[v] && g->distance[u][v] < cost[v]) {
cost[v] = g->distance[u][v];
parent[v] = u;
}
}
}
printf("最小生成树(Prim算法):\n");
int totalCost = 0;
for (int i = 0; i < g->cityCount; i++) {
if (i != start) {
printf("第%d条边 %s——>%s %d公里\n", i, g->city[parent[i]], g->city[i], g->distance[parent[i]][i]);
totalCost += g->distance[parent[i]][i];
}
}
printf("总代价: %d公里\n", totalCost);
}
int main() {
Graph g;
if (!readGraph(&g, "graph.txt")) {
return 1;
}
for (int i = 0; i < g.cityCount; i++) {
printf("以%s为起点的最小生成树:\n", g.city[i]);
prim(&g,i);
printf("\n");
}
return 0;
}
代码解释:
这段代码实现了一个简单的图结构,并使用Prim算法来生成最小生成树(MST)。代码分为几个部分:定义图结构、读取图数据、实现Prim算法、以及主函数。下面我将逐步讲解这段代码。
-
包含头文件和宏定义
#include <stdio.h> #include <stdlib.h> #include <string.h> #include <bits/stdc++.h> #define INF 999999 #define MAX 20
#include <stdio.h>
和#include <stdlib.h>
提供了标准输入输出和标准库函数。#include <string.h>
提供了字符串处理函数。#include <bits/stdc++.h>
包含了几乎所有的C++标准库头文件(实际中在C代码中不推荐这样做)。#define INF 999999
定义了一个大的常数,用来表示两个城市之间不存在直接路径。#define MAX 20
定义了最大城市数量。 -
定义图结构
typedef struct { char city[MAX][20]; int distance[MAX][MAX]; int cityCount; } Graph;
结构体
Graph
定义了一个图,包含:city[MAX][20]
:存储城市名称。distance[MAX][MAX]
:存储城市之间的距离。cityCount
:记录城市数量。
-
读取图数据
int readGraph(Graph *g, const char *filename) { FILE *file = fopen(filename, "r"); if (!file) { printf("无法打开文件\n"); return 0; } g->cityCount = 0; for (int i = 0; i < MAX; i++) { for (int j = 0; j < MAX; j++) { g->distance[i][j] = INF; } } char city1[20], city2[20]; int dist; while (fscanf(file, "%s %s %d", city1, city2, &dist) == 3) { int index1 = -1, index2 = -1; for (int i = 0; i < g->cityCount; i++) { if (strcmp(g->city[i], city1) == 0) { index1 = i; } if (strcmp(g->city[i], city2) == 0) { index2 = i; } } if (index1 == -1) { strcpy(g->city[g->cityCount], city1); index1 = g->cityCount++; } if (index2 == -1) { strcpy(g->city[g->cityCount], city2); index2 = g->cityCount++; } g->distance[index1][index2] = dist; g->distance[index2][index1] = dist; } fclose(file); return 1; }
打开指定的文件并检查是否成功。
初始化
distance
数组中的所有值为INF
。读取文件中的城市对和距离,并填充
city
和distance
数组。查找城市索引,如果城市是新的,则添加到城市列表中并更新
cityCount
。关闭文件并返回成功标志。
-
Prim算法实现(核心代码)
void prim(Graph *g, int start) { int cost[MAX], visited[MAX], parent[MAX]; for (int i = 0; i < g->cityCount; i++) { cost[i] = INF; visited[i] = 0; parent[i] = -1; } cost[start] = 0; for (int i = 0; i < g->cityCount - 1; i++) { int minCost = INF, u = -1; for (int j = 0; j < g->cityCount; j++) { if (!visited[j] && cost[j] < minCost) { minCost = cost[j]; u = j; } } visited[u] = 1; for (int v = 0; v < g->cityCount; v++) { if (!visited[v] && g->distance[u][v] < cost[v]) { cost[v] = g->distance[u][v]; parent[v] = u; } } } printf("最小生成树(Prim算法):\n"); int totalCost = 0; for (int i = 0; i < g->cityCount; i++) { if (i != start) { printf("第%d条边 %s——>%s %d公里\n", i, g->city[parent[i]], g->city[i], g->distance[parent[i]][i]); totalCost += g->distance[parent[i]][i]; } } printf("总代价: %d公里\n", totalCost); }
初始化
cost
(用于存储每个城市到生成树的最小边的权重)、visited
(记录每个城市是否已被包含在生成树中)、parent
(存储每个城市在生成树中的父节点)。设置起始城市的
cost
为0。在每一轮中,找到
cost
最小且未访问的城市u
,并将其标记为已访问。更新从
u
到其他未访问城市的cost
和parent
。打印生成的最小生成树和总的权重。
-
主函数
int main() { Graph g; if (!readGraph(&g, "graph.txt")) { return 1; } for (int i = 0; i < g.cityCount; i++) { printf("以%s为起点的最小生成树:\n", g.city[i]); prim(&g, i); printf("\n"); } return 0; }
创建一个
Graph
实例g
。读取图数据,如果失败则返回错误。
对于每个城市作为起点,调用
prim
函数计算并打印最小生成树。总结
这段代码实现了读取图数据并使用Prim算法生成最小生成树。代码中处理了图的初始化、数据读 取、Prim算法的执行以及结果的输出。可以根据需要调整图的数据文件并运行程序以查看结果。