Prim最小生成树是一个动态的过程,
并不是一次性把所有结点的最小的key都算出来然后一个一个往最小生成树里面加,
而是先选定一个结点,让他最小成为第一个加进去,以此为基础开始循环,更新key的值,
每次都加入当前最小的并且没有被加入的,每一次循环都在更新,直到把所有的都加进去。
代码几乎是抄的,因为我没有写出来…
修改了一些,加了些注释,让输出清楚完整一些,改的有点不像C++了…
修改前的源码是这位博主的:https://blog.csdn.net/I_am_a_winer/article/details/45276643
贴下新的代码:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#define INF 0x7fffffff
using namespace std;
int Map[110][110], dis[110], vis[110];
//map就是存两点权值的矩阵,注意:二维数组的下标刚好是两个结点的值。dis相当于书上的key,是不断更新的当前结点相连的边的最小权重,vis记录结点是否已经被访问
int N, M;
void prime(int s) {
printf("路径\n");
memset(vis, 0, sizeof(vis)); //初始化访问的数组都为0
for (int i = 1; i <= N; i++) //每个结点的权值都初始化为与1的之间边的权值
dis[i] = Map[1][i]; //权值可以理解成距离,似乎更好理解
int sum = 0;
vis[s] = s;
printf("%d ", s);
for (int p = 1; p <= N - 1; p++) { //进行N-1次循环,加入剩下的N-1个点
int t, Min = INF;
for (int i = 1; i <= N; i++)
if (!vis[i] && dis[i]<Min) //如果没有访问过这个结点并且他的值小于min //寻找集合1-S中到集合S最近的点t
Min = dis[i], t = i; //最小值就变成他并且记录他的下标i
sum += Min; vis[t] = 1; //找到那个当前的最小值之后,把标记他为已经访问,然后再把权值加到路径里面去
printf("%d ", t);
for (int i = 1; i <= N; i++)
if (!vis[i] && dis[i]>Map[t][i]) //更新与t相连且在1-S中的点到集合S的距离
dis[i] = Map[t][i];
}
printf("\n最小生成树权值:\n");
cout << sum << endl;
}
int main() {
int s;
//freopen("D:\\in.txt","r",stdin);
printf("输入结点个数:\n");
while (cin >> N && N) {
for (int i = 0; i <= N; i++) //初始化矩阵为最大值
for (int j = 0; j <= N; j++)
Map[i][j] = INF;
printf("输入边的条数:\n");
scanf_s("%d", &M);
printf("输入第一个点:\n");
scanf_s("%d", &s);
// M = (N - 1)*N / 2;
printf("输入两点和权重(逗号分隔)\n");
int a, b, c;
for (int i = 0; i<M; i++) {
scanf_s("%d,%d,%d", &a, &b, &c);
Map[a][b] = Map[b][a] = c; //注意无向图在给矩阵赋值的时候是双向的
}
prime(s);
}
return 0;
}
测试数据来自算法导论,是没有问题的。把abc改成123这样的。