Prim算法
Prim 算法和 Dijkstra 算法很相似,都是从一个点开始把点不停加入到点集合。
Prim算法适合于边疏密的图。
首先定义邻接矩阵、标志数组和一个不断更新的 minCost 数组用来求当前点集到其他点的最小权值。
#define N 6
vector<vector<int> > Graph(N,vector<int>(N,INT_MAX));//邻接矩阵
vector<bool> visited(N,false); //访问标记数组
vector<int> minCost(N,INT_MAX); //从顶点集x出发到每个顶点的最小权值
int res = 0; //最小生成树的权值之和
Prim 函数和 Dijkstra 算法基本相同。
int Prim(int v){
minCost[v] = 0; //v开始
while(true){
int v = -1;
for(int u = 0;u < N;u ++)
if(!visited[u] && (v == -1 || minCost[u] < minCost[v])) v = u;
if(v == -1) break;
visited[v] = true;
cout<<"v"<<v+1<<"加入顶点集"<<endl;;
res += minCost[v]; //权值++
for(int u = 0;u < N;u ++)
minCost[u] = min(minCost[u],Graph[v][u]); //权值表更新
}
return res;
}
完整代码如下:
#include<iostream>
#include<vector>
using namespace std;
#define N 6
vector<vector<int> > Graph(N,vector<int>(N,INT_MAX));//邻接矩阵
vector<bool> visited(N,false); //访问标记数组
vector<int> minCost(N,INT_MAX); //从顶点集x出发到每个顶点的最小权值
int res = 0; //最小生成树的权值之和
int Prim(int v){
minCost[v] = 0; //v开始
while(true){
int v = -1;
for(int u = 0;u < N;u ++)
if(!visited[u] && (v == -1 || minCost[u] < minCost[v])) v = u;
if(v == -1) break;
visited[v] = true;
cout<<"v"<<v+1<<"加入顶点集"<<endl;;
res += minCost[v];
for(int u = 0;u < N;u ++)
minCost[u] = min(minCost[u],Graph[v][u]);
}
return res;
}
int main(){
Graph[0][2] = 10;
Graph[2][0] = 10;
Graph[0][4] = 30;
Graph[4][0] = 30;
Graph[0][5] = 100;
Graph[5][0] = 100;
Graph[1][2] = 5;
Graph[2][1] = 5;
Graph[2][3] = 50;
Graph[3][2] = 50;
Graph[3][5] = 10;
Graph[5][3] = 10;
Graph[4][3] = 20;
Graph[3][4] = 20;
Graph[4][5] = 60;
Graph[5][4] = 60;
int v = 0;
cout<<Prim(v);
}
运行结果:
与 Dijkstra 算法相同,Prim 的时间复杂度为O(N*N),若在查找最小权值时构造一个堆来实现,时间复杂度可以优化到O(NlogN),此时与 Kruskal 算法的时间复杂度相近。
Prim 算法也属于贪心算法。