基于MST性质的Prim算法求最小生成树

版权声明:本文为博主原创文章,转载请附明出处^_^ https://blog.csdn.net/cprimesplus/article/details/90214800

最小生成树的概念

假设在 n 个城市间修路,则联通 n 个城市只需要 n-1 条道路。目的是让道路的总花销最少,求最佳方案。

 

MST的性质

MST(Most Spanning Tree)性质即:

最小生成树性质:设G=(V,E)是一个连通网络,U是顶点集V的一个非空真子集。若(u,v)是G中一条“一个端点在U中(例如:u∈U),另一个端点不在U中的边(例如:v∈V-U),且(u,v)具有最小权值,则一定存在G的一棵最小生成树包括此边(u,v)。

用白话描述即:

对于联通网的所有结点构成的集合,从中任取一个子集记为 u,集合减去这个子集构成的小集合记为 v。从 u 到 v 找到一条权值最小的路径,则此路径一定属于这个联通网的最小生成树。

 

MST性质的证明与理解

反证法,见严蔚敏版《数据结构》P173.

对Prim算法的一点理解:

为什么这样构成的结构是一棵树(没有环)?通过思考Prim算法的步骤可以发现:

(1)最初点集 u 中只有一个元素时,新加入一个结点构成的路径不可能成环。

(2)当 u 中结点不少于3个时,再加入一条路径不可能为环,因为之前可能与新放入的结点构成环的结点已经被放入了 u中。

 

Prim算法最小生成树代码

// Prime算法求图的最小生成树
#include<iostream>
#include<cstring>
#define MAX_SIZE 128
#define INF 0x3f3f3f3f
using namespace std;
int Graph[MAX_SIZE][MAX_SIZE], vexnum; 
int MSTByPrim()
{
	int vis[MAX_SIZE];   // 辅助数组,用来记录一个点是否已经被加入到割集U,不加这个辅助数组的话还需要再遍历U 判断一个点是否在U 中
	int U[MAX_SIZE];
	memset(vis, 0 ,sizeof(vis));
	vis[0] = 1;			// 最初放入顶点A
	U[0] = 0;
	int res = 0;
	int index = 1;
	while(index < vexnum)
	{
		int min_val = INF, temp = 0, markU = 0;
		for(int i = 0;i < index;i++){
			for(int j = 0;j < vexnum;j++){
				if(!vis[j] && Graph[U[i]][j]<min_val){
					min_val = Graph[U[i]][j];
					markU = U[i];
					temp = j;	
				}
			}
		}
		cout<<(char)(markU+'A')<<"-->"<<(char)(temp+'A')<<' '<<min_val<<endl;
		vis[temp] = 1;
		res += min_val;
		U[index++] = temp;
	}
	return res;
}
int main()
{
	cin>>vexnum;
	for(int i = 0;i < vexnum;i++)
		for(int j = 0;j < vexnum;j++){
			 cin>>Graph[i][j];
			 if(!Graph[i][j]) Graph[i][j] = INF;
		}
	cout<<MSTByPrim();
	return 0;
}                                      

测试用例及结果

猜你喜欢

转载自blog.csdn.net/cprimesplus/article/details/90214800