最小生成树----Prim算法



prim算法是利用最小生产树的MST性质来一点一点的构造最小生成树的。

假设N={V,{E}}是一个带权值的无向图(即为一个网),U是顶点集V的一个非空子集,  若(u,v)是一个具有最小权值的边,其中u属于U,v属于V-U,则必然存在一个包含(u,v)边的最小生成树。

关于MST的证明:点击打开链接


prim算法分析:(使用邻接矩阵来存储网)

1:要知道T1顶点集合连接到T2顶点集合中最小权值的边,就是从T1集合中选一个顶点t1,从T2集合分钟选一个顶点,使得(t1,t2)的权值最小,其中T2集合是已经构成最小生成树一部分的顶点。

2:要知道T1中哪个顶点和T2中哪个顶点构成的边具有最小权值。

解决一问题使用:lowcost[MAX]数组,用来记录可能权值最小的顶点和权值信息。比如lowcost[k] = 78,就表示T2顶点集合中的某个顶点和第k个顶点(来自于T1)组成的边权值是78,有可能是最小的权值。

解决二,使用lowcost[MAX],我们知道了T1集合的第k个顶点和T2中的某个顶点可能构成最小权值边,但是我们不知道T2中的某个点是哪个,所以我们可以使用vertex[MAX]来记录。

如果单纯的要计算最少的代价总和,而不要记录顶点的顺序,就不需要vertex数组了。



如果从顶点v1开始构建最小生成树进行如下步骤:

1:初始化lowcost和vertex数组

for (int i = 1;i <= n;i++)

 {

lowcost[i] = Matrix[1][i];//v1与邻接点构成的边的权值。

vertex[i] = 1;

}

lowcost[1] = 0;//表示v1顶点加入了T2集合中,

2:遍历lowcost[MAX]数组,选择其中值最小的且值不为0的权值所在的下标k,然后lowcost[k] = 0;表示将第k个顶点加入T2集合中,我们可以打印出此时的边

printf ("%d %d %d",vertex[k],k,lowcost[k]);//这个时候vertex就有用了。

3:进行到这里我们知道第k个顶点加入集合T2中了,这个要改变lowcost和vertex,

for (i = 1;i <= n;i++) {

if (lowcost[i] != 0 && Matrix[k][i] < lowcost[i]) {

lowcost[i] = Matrix[k][i];

vertex[i] = k;

}

}

2,3步骤是一个在T1中取顶点的过程,不断的进行2,3步骤直至U=V为止,这个就完成的了最小生成的树的构造。

#include "stdio.h"
#include "string.h"


#define MAX 20

#define INF 100000000

int Matrix[MAX][MAX];


//n顶点的数量,v表示从第几个顶点开始构造最小生成树
int minimum_cost_spanning_tree (int n,int v) {
	int least_weight_sum = 0;
	int lowcost[MAX];
	int vertex[MAX];
	int i,j;
	for (i = 1;i <= n;i++) {
		lowcost[i] = Matrix[v][i];
		vertex[i] = v;	
	}
	lowcost[v] = 0;//表示将Vv加入U集合中
	for (i = 1;i < n;i++) {//从V-U集合筛选出顶点放入U集合中
			int min = INF;
			for (j = 1;j <= n;j++) {
				if (lowcost[j] != 0 && lowcost[j] < min) {
					min =  lowcost[j];
					v = j;
				}
			}
			printf ("%d %d %d\n",vertex[v],v,lowcost[v]);
			least_weight_sum  += lowcost[v];
			lowcost[v] = 0;//表示将Vv加入U集合中
			for (j = 1;j <= n;j++) {
				if (Matrix[v][j] < lowcost[j]) {
					lowcost[j] = Matrix[v][j];
					vertex[j] = v;
				}
			}
	}		
	return least_weight_sum;
}
void print (int n) {
	int i;
	int j;
	for (i = 1;i <= n;i++) {
		for (j = 1;j <= n;j++){
			printf ("%10d ",Matrix[i][j]);
		}
		printf ("\n");
	}
}

int main () {
	
	int i,j;
	int n,m;//n边数,m顶点数
	int v,u,w;//v和u表示某条边依附的二个顶点 w为权值
	memset (Matrix,0,sizeof(Matrix));
	scanf ("%d%d",&n,&m);
	for (i = 0;i <n;i++) {
			scanf ("%d%d%d",&v,&u,&w);
			Matrix[v][u] = Matrix[u][v] = w;
	}
	for (i = 1;i <= m;i++) {
		for (j = 1;j <= m;j++) {
			if (i != j && Matrix[i][j] == 0) {
				Matrix[i][j] = INF;
			}
		}
	}
	print (m);
	printf ("-------\n");
	minimum_cost_spanning_tree (m,1);
	return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值