版权声明:本文为博主原创文章,转载请附明出处^_^ https://blog.csdn.net/cprimesplus/article/details/90214800
最小生成树的概念
假设在 个城市间修路,则联通 个城市只需要 条道路。目的是让道路的总花销最少,求最佳方案。
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;
}
测试用例及结果