最小生成树Prim算法-邻接矩阵

最小生成树

在我第n次画图之后终于把prim搞出来了,鼓掌!!!

首先来介绍下最小生成树

在给定的n个节点之间,每条路径之间都有相应的权值,最小生成树就是找到连接所有节点且权值之和最小。

请添加图片描述

找到最小生成树最常用的算法有Prim算法和Kruskal算法,这里介绍Prim

Prim算法

思想:

把整个图分为两块,已选中块未选中块,用一个数组parent记录到达当前节点的父节点是什么,另一个数组vertext记录父节点到当前节点的路径权值顺带记录下是不是访问过该节点,从初始结点开始,每次通过遍历vertext找到全局里面从已选中块延伸到未选中块的最小权值边,把最小权值边连接的节点划进已选中块,进行新一轮寻找。默认是从0节点是初始结点,为了方便寻找parent数组里存的都是下标,额外会用一个矩阵b存储所有路径权值。

图解:

  1. 构建矩阵b及两个数组:我比较懒就用vertext去记录是不是访问过该节点,其实可以另开一个数组,具体如果该节点被访问过vertext存1000(前提1000比所有权值都大)

    请添加图片描述

  2. 注:图中绿色圈为选中块,ABCDE 对应 parent 中的 01234

    默认初始结点A,选中块只有a,选中块延伸出三条边,最小权值1,因此选择路径A-E

    请添加图片描述

  3. 将新划分进已选块的E节点连接未选块的路径添加进vertext数组,如果数组已经有权值,比较原有值和新值大小,及时更新数组,还是选最小权值路径A-C

    请添加图片描述

  4. 重复同2,3一样的操作,最终会得到如下请添加图片描述

代码:

#include <bits/stdc++.h>
using namespace std;
int main () {
    //这里都是前期准备工作,没得啥用
	int n, m;
	int parent[100]; //父节点 
	int vertext[100] = {0}, b[100][100];  //记录是否被访问过||访问权值,访问过 1000 , b是矩阵 
	cin >> n >> m;
	char a[n];
	for (int i = 0; i < n; i ++) {
		cin >> a[i];
	}
	for (int i = 0; i < m; i ++) {
		int x, y, z;
		cin >> x >> y >> z;
		b[x][y] = z;
		b[y][x] = z;
	}
	int min = 0, sum = 1;	//min记录最小权值下标,默认0 
	vertext[0] = 1000;
    
    //下面才是prim过程
	for (int i = 0; sum < n;) {
		for (int j = 0; j < n; j ++) {	//寻找与节点i相连的节点 
			if (b[i][j] > 0 && vertext[j] != 1000) {    //相连且未被访问节点j 
				if (vertext[j] > b[i][j] || vertext[j] == 0) { //权值比原先小或者未曾有过权值 
					parent[j] = i;	//父节点i 
					vertext[j] = b[i][j];		//改为小权值 
				}
			}		
		}
		for (int j = 0; j < n; j ++) {
			if (vertext[min] > vertext[j] && vertext[j] != 0) {  //当前节点参选条件为有权值 
				min = j;
			}
		}
		cout << a[parent[min]] << " " << a[min] << " " << vertext[min] << endl;
		vertext[min] = 1000;		//设置最小权值为以访问状态 
		sum ++;
		i = min;   //节点min为新加入选中块的节点,下一次循环从这里开始 
		min = 0; 
	}
	return 0; 
} 
/*测试
5 7
A B C D E
0 1 6
0 2 2
0 3 1
1 2 4
1 3 3
2 4 6
3 4 7
*/

/*结果
A D 1
A C 2
D B 3
C E 6
*/

最后的最后我只想说,算法令人难过,要保护好自己的头发,

  • 3
    点赞
  • 17
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值