算法步骤:
假设N=(V,{E})是连通图,TE是N上最小生成树中边的集合。算法从U={u0}(u0∈V),TE={}开始,
重复执行下述操作:
在所有u∈U,v∈V-U的边(u,v)∈E中找一条代价最小的边(u0,v0)并入集合TE,同时v0 并入U,直至U=V为止。
此时TE中必有n-1条边,则T=(V,{TE})为N的最小生成树。
具体步骤如下:
1) 创建一个集合mstSet记录已经包含在MST中的顶点
2)对图中的所有顶点设置一个key值,代表代价,并初始化无穷大。第一个点设置为0,以便总
是能第一个取到第一个点
3) While( mstSet没有包含所有的顶点 )
a) 从mstSet集合中剩下的顶点中,选取一个最小key的顶点u
b) 把u加入到mstSet
c) 更新所有的和u相连的那些顶点的key值。
算法实例:
初始的mstSet为空,keys(各个点击的代价)为{0, INF, INF, INF, INF, INF, INF, INF,INF}
找到其中最小的,并加入mstSet,mstSet变为: {0}. 然后更新和0相邻的那些顶点的key值。相邻的顶点为1和7. 更新后为 {0, 4, INF, INF, INF, INF, INF, 8,INF}
MST中的顶点由绿色表示
选择keys最小并且不在mstSet中的顶点,顶点1加入。因此mstSet更新为 {0, 1}。更新与1相邻的顶点的key值。顶点2的key值更新为8。
keys更新后为 {0, 4, 8, INF, INF, INF, INF, 8,INF}
选择keys最小并且不在mstSet中的顶点,我们可以选择顶点7或2,将7加入。因此mstSet更新为 {0, 1,7}。更新与7相邻的顶点的key值。顶点6和8的key值分别更新为1和7。keys更新后为 {0, 4, 8, INF, INF, INF, 1, 8,7}。
选择keys最小并且不在mstSet中的顶点,顶点6加入。因此mstSet更新为 {0, 1,7,6}。更新与6相邻的顶点的key值。顶点5和8的key值分别更新为2和6。keys更新后为 {0, 4, 8, INF, INF, 2, 1, 8,6}。
重复上面的过程,最终得到MST为
算法实现:
#include <iostream>
#include <limits.h>
using namespace std;
#define V 5//图中顶点个数
//从不在mstSet中的点组成的集合中,找出最小key的点,返回其下标
int minKey(int key[], bool mstSet[])
{
int min=INT_MAX, min_index;
for(int v=0;v<V;v++)
{
if(mstSet[v]==false&&key[v]<min)
{
min=key[v];
min_index=v;
}
}
return min_index;
}
// Prim算法
void primMST(int graph[V][V])
{
int parent[V];// 保存MST信息
int key[V];// 所有顶点的代价值
bool mstSet[V];//当前包含在MST中点的集合
// 初始为无穷大,并且都不在mstSet中
for(int i=0;i<V;i++)
{
key[i] = INT_MAX, mstSet[i] = false;
}
key[0]=0;//Make key 0 so that this vertex is picked as first vertex
parent[0]=-1;// First node is always root of MST
// 顶点0已经加入MST,则只需再加入V-1个顶点即可
for(int count=0;count<V-1;count++)
{
int u=minKey(key,mstSet);
mstSet[u]=true;
//更新和u相连的顶点的代价
for(int v=0;v<V;v++)
{/*更新的前提:和u相连(u本身以及与u不可达的点的graph都为0)
&& 不在mstSet[]中
&& 其graph < 当前key值*/
if(graph[u][v]&&mstSet[v]==false&&graph[u][v]<key[v])
{
parent[v]=u, key[v]=graph[u][v];
}
}
}
// print the constructed MST
cout<<"得到MST的边和对应权重如下:"<<endl;
for(int i=1;i<V;i++)
{
cout<<parent[i]<<"--"<<i<<" "<<graph[i][parent[i]]<<endl;
}
}
int main()
{
/* Let us create the following graph
2 3
(0)--(1)--(2)
| / \ |
6| 8/ \5 |7
| / \ |
(3)-------(4)
9 */
int graph[V][V] = {{0, 2, 0, 6, 0},
{2, 0, 3, 8, 5},
{0, 3, 0, 0, 7},
{6, 8, 0, 0, 9},
{0, 5, 7, 9, 0},
};
// Print the solution
primMST(graph);
return 0;
}
执行结果:
得到MST的边和对应权重如下:
0--1 2
1--2 3
0--3 6
1--4 5
时间复杂度:O(V^2). 如果使用 链接表存储的方式并使用堆,复杂度可以为 O(E log V) 。
参考:http://www.geeksforgeeks.org/greedy-algorithms-set-5-prims-minimum-spanning-tree-mst-2/