题目描述
【问题描述】用prim算法思想求一个给定无向连通网的最小生成树。
【输入形式】无向连通网的顶点数,起始顶点及无向连通网各边的权值。
【输出形式】第1行为顶点数,第2行为起始顶点;接着若干行为无向连通网各边的信息。0表示不存在顶点到自身的边,32767表示两个顶点之间不存在边。(样例输入的第1行表示图有6个顶点,第2行表示从顶点0出发)
【样例输入】
6
0
0 5 8 7 32767 3
5 0 4 32767 32767 32767
8 4 0 5 32767 9
7 32767 5 0 5 32767
32767 32767 32767 5 0 1
3 32767 9 32767 1 0
【样例输出】
普里姆算法求解结果:
边(0,5)权为:3
边(5,4)权为:1
边(0,1)权为:5
边(1,2)权为:4
边(4,3)权为:5
最小生成树的代价为:18
解题思路
- 选择一个起始节点作为最小生成树的起点。
- 将该起始节点加入最小生成树集合,并将其标记为已访问。
- 在所有与最小生成树集合相邻的边中,选择权重最小的边和它连接的未访问节点。
- 将该边和节点加入最小生成树集合,并将该节点标记为已访问。
- 重复步骤3和步骤4,直到最小生成树集合包含了图中的所有节点。
源代码
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#define MAX 100
#define INF 32767
void prim(int n, int start, int cost[][MAX], int dist[], int path[]) {
int i, j, k, min, minid, sum = 0;
// 初始化dist和path数组
for (i = 0; i < n; i++) {
dist[i] = cost[start][i];
path[i] = start;
}
for (i = 1; i < n; i++) {
min = INF;
minid = -1;
// 找出当前dist数组中最小值对应的顶点
for (j = 0; j < n; j++) {
if (dist[j] != 0 && dist[j] < min) {
min = dist[j];
minid = j;
}
}
if (minid == -1) {
printf("无法构成最小生成树\n");
return;
}
// 将最小生成树的边输出
printf(" 边(%d,%d)权为:%d\n", path[minid], minid, min);
sum += min;
dist[minid] = 0;
// 更新dist和path数组
for (k = 0; k < n; k++) {
if (dist[k] != 0 && cost[minid][k] < dist[k]) {
dist[k] = cost[minid][k];
path[k] = minid;
}
}
}
printf("最小生成树的代价为:%d\n", sum);
}
int main() {
int n, start, i, j;
int cost[MAX][MAX], dist[MAX], path[MAX];
scanf("%d", &n);
scanf("%d", &start);
for (i = 0; i < n; i++) {
for (j = 0; j < n; j++) {
scanf("%d", &cost[i][j]);
}
}
printf("普里姆算法求解结果:\n");
prim(n, start, cost, dist, path);
return 0;
}
总结
求取最小生成树算法,是数据结构图部分的经典算法。