prim属于贪心算法,因为每一步所加入的边都使总的权重量增加最小。
算法步骤:
- 创建一个数组mstSet用来记录节点是否包含在生成树中,key数组记录最小的权重,parent数组记录生成树
- 为每个点的权重值赋值为最大,为第一个赋值为0,我们以一个为根节点生成树
- 遍历相邻的顶点,对于每个相邻顶点权重值小于先前的key
我们通过以下实例来理解此算法:
mstSet最初为空,分配给顶点的键为{0,INF,INF,INF,INF,INF,INF,INF},其中INF表示无穷大。现在选择具有最小键值的顶点。挑选顶点0,将其包含在mstSet中。包含到mstSet后,更新相邻顶点的键值。相邻顶点0为1和7.键值1和7更新为4和8.MST中包含的顶点以绿色显示。
选择最小的键值并且不在mstSet中,将顶点1存入mstSet。把顶点1的相邻顶点2的键值为8
选择最小的键值并且不在mstSet中,我们可以选择顶点2或7.假如选择顶点7,那就修改相邻顶点6和8的键值
扫描二维码关注公众号,回复:
2850643 查看本文章
以此类推我们可以得到生成树
图片来源Geeeks
c++代码实现
#include <bits/stdc++.h>
#define V 5
using namespace std;
int minKey(int *key,bool *mstSet)
{
int min = INT_MAX;
int index = 0;
for(int i = 0; i < V; i++)
{
if(!mstSet[i] && min > key[i])
{
min = key[i];
index = i;
}
}
return index;
}
void printMST(int *parent,int graph[V][V])
{
for(int i = 1; i < V; i++)
cout << parent[i] << "-" << i << " " << graph[i][parent[i]] << endl;
}
void prim(int graph[V][V])
{
int parent[V];//存储父节点
int key[V];//存储最小的权重
bool mstSet[V];//是否包含在生成树中
for(int i = 0; i < V; i++)
{
key[i] = INT_MAX;
mstSet[i] = false;
}
parent[0] = -1;
key[0] = 0;
int i = 0;
while(i < V-1)
{
int index = minKey(key,mstSet);
mstSet[index] = true;
for(int k = 0; k < V; k++)
{
if(graph[index][k] && !mstSet[k] && graph[index][k] < key[k])
{
parent[k] = index;
key[k] = graph[index][k];
}
}
i++;
}
printMST(parent,graph);
}
int main(void)
{
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},
};
prim(graph);
return 0;
}