prim算法

   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;
}

ceshi
这就是测试点信息

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值