prim算法是用来求最小生成树的算法,什么是最小生成树呢?
对于一张n个点带权图,它的生成树就是用其中的n-1条边来连接这n个点,那么最小生成树就是n-1条边的边权之和最小的一种方案,简单的理解,就是用让这张图只剩下n-1条边,同时这n-1条边的边权总和最小。
prim算法的思想就是将n个顶点分为两类,树顶点和非树顶点,首先任意选择一个顶点加入生成树,接下来要枚举每一个树顶点到每一个非树顶点所有边,然后找到最短边加入到生成树中,照此方法,重复操作n-1次,直到将所有的点都加入到生成树中。因为prim 是对点进行操作,所以适合稠密图。
如何找到每一个树顶点到非树顶点的所有边并且得到最短边呢?
我们用dis数组来记录各个顶点到"生成树”最短距离,不是每个顶点到一号顶点的最短距离,是每个顶点到任意一个生成树顶点的最短距离。我们也需要book数组来标记哪些顶点已经被加入到生成树中,避免重复
接下来是邻接矩阵的prim算法
先初始化邻接矩阵
for (i = 1; i <= n; i++) {
for (j = 1; j <= n; j++) {
if (i == j) e[i][j] = 0;
else e[i][j] = inf;//inf表示无穷大
}
}
开始读入边和权,这里是无向图
for (i = 1; i <= m; i++) {
scanf("%d %d %d", &t1, &t2, &t3);
//t1,t2是顶点,t3是权
e[t1][t2] = t3;
e[t2][t1] = t3;
}
初始化dis数组为第一个顶点到其他各个顶点间的距离,如果第一个顶点与当前点之间没有联系,则距离是inf
for (i = 1; i <= n; i++)
dis[i] = e[1][i];
控制整个循环的是n-1,因为本来有n个顶点,现在先选一个顶点加入到生成树中,所以只剩下n-1个了。
book[1] = 1;//将第一个顶点标记为已经在最小生成树中
count++;
while (count < n){
min = inf;
//找出距离生成树最短的顶点的下标,dis[i]表示顶点i到生成树的距离
for (i = 1; i <= n; i++) {
if (book[i] == 0 && dis[i] < min) {
min = dis[i];
j = i;
}
}
count++;
book[j] = 1;//标记这个点
sum = sum + dis[j];//sum表示最小生成树的权值总和
for (k = 1; k <= n; k++) {
//如果k没有在最小生成树中并且k顶点到以前最小生成树的距离大于k顶点到j顶点的距离,
//就更新dis数组,dis[k]表示K顶点到最小生成树之间的距离,这个更新其实就是更新没在生成树中的点到生成树之间的距离
if (book[k] == 0 && dis[k] > e[k][j])
dis[k] = e[K][j];
}
}
接下来就是完整的prim算法的代码
#include<stdio.h>
//prim算法的思想就是不断扩大最小生成树,并且更新最小生成树到其他顶点的距离
int main(void) {
int n, m, i, j, k, min, t1, t2, t3;
int e[7][7], dis[7], book[7] = { 0 };
int inf = 99999;
int count = 0, sum = 0;
scanf("%d %d", &n, &m);//n表示顶点个数,m表示边数
//初始化邻接矩阵
for (i = 1; i <= n; i++) {
for (j = 1; j <= n; j++) {
if (i == j) e[i][j] = 0;
else e[i][j] = inf;
}
}
for (i = 1; i <= m; i++) {
scanf("%d %d %d", &t1, &t2, &t3);
//t1,t2是顶点,t3是权
e[t1][t2] = t3;
e[t2][t1] = t3;
}
//初始化dis数组为第一个顶点到与他相邻的顶点的权,初始化不用管,
//dis数组存的是生成树到非生成树间的权值最小值
for (i = 1; i <= n; i++)
dis[i] = e[1][i];
book[1] = 1;
count++;
//先把第一个顶点标记
while (count < n) {
min = inf;
//找出距离生成树最短的顶点的下标
for (i = 1; i <= n; i++) {
if (book[i] == 0 && dis[i] < min) {
min = dis[i];
j = i;
}
}
count++;
book[j] = 1;//标记这个点
sum = sum + dis[j];
for (k = 1; k <= n; k++) {
if (book[k] == 0 && dis[k] > e[K][j])
dis[k] = e[k][j];
}
}
for (i = 1; i <= n; i++) {
printf("%d", dis[i]);
}
printf("\n%d", sum);
return 0;
}
这就是测试点信息