Prim算法的核心思想是"贪心" ,首先最小生成树是一个带权的无向图(最小生成树: n个顶点有n-1条边)。构建最小生成树就是要在带权边上选择最小权的边。首先置S = {1},然后只要S是V的真子集,就做如下贪心选择。选取满足条件i属于S,j属于V-S。且g.arac[i][j]最小的边 。并将符合条件的j顶点添加到S中。直到S = V为止。此过程选取到的边则为构成最小生成树的边。
最小生成树的目的是为了把所有点包进这个网络中,并且网络中的边最短。常用算法有Prim,Kruskal算法。注意与単源最短路径区分。单源最短路径的目的是从一个源节点想方设法找到一条到目的节点的路径。常用算法有:Dijkstra算法。
最小生成树是整体来分析,而单源最短路径是单条路径来分析的。
代码:
Prim算法:
void Prim(graph &g){
int min_cost = 0;
int lowcost[NUM]; //当前最短距离
int closest[NUM]; //顶点的相邻顶点(closest[i]则为i的邻接点)
int s[NUM]; //标志访问节点
for(int i = 1;i<=g.v;i++){
closest[i] = 1; //初始置各顶点得邻接点为1
lowcost[i] = g.arac[1][i]; //初始置各顶点的最短距离为1到顶点的距离
s[i] = 0;
}
for(int i = 1;i<g.v;i++){
int min = INIT; //min初始化无穷大
int j = 1;
for(int k = 2;k<=g.v;k++){
if(lowcost[k]<min&&!s[k]){ //找出与源点相连,且权值最小的顶点
min = lowcost[k]; j = k;
}
else{
;
}
}
min_cost+=min;
cout<<closest[j]<<"->"<<j<<endl; //输出符合最小生成树的顶点
s[j] = 1; //已访问顶点置1
for(int t = 2;t<=g.v;t++){
if(g.arac[j][t]<lowcost[t]&&!s[t]){ //从新添加的顶点j出发,将与j相邻的顶点间的权值
//与上一顶点的相邻顶点间的权值进行比较。选出最小权值和相应顶点.
lowcost[t] = g.arac[j][t];
closest[t] = j;
}
else{
;
}
}
}
cout<<"最小生成树得最短路径为:"<<min_cost<<endl;
}
完整代码:
/**
@ 最小生成树-Prim算法
*/
#include<iostream>
#include<algorithm>
#include<cstdlib>
#define INIT 63355
#define NUM 20
using namespace std;
typedef int Elemtype;
typedef struct Tnode{
Elemtype vex[NUM];
int arac[NUM][NUM];
int v,e;
}graph;
void Init_Graph(graph &g){
for(int i = 1;i<=g.v;i++){
for(int j = 1;j<=g.v;j++){
g.arac[i][j] = INIT;
}
}
}
void Create_Graph(graph &g){
cout<<"输入顶点,边数目:"<<endl;
cin>>g.v>>g.e;
Init_Graph(g);
cout<<"输入顶点信息:"<<endl;
for(int i = 1;i<=g.v;i++){
cin>>g.vex[i];
}
cout<<"输入顶点间下标和权值:"<<endl;
int k,t,w;
for(int i = 1;i<=g.e;i++){
cin>>k>>t>>w;
g.arac[k][t] = w;
g.arac[t][k] = g.arac[k][t];
}
}
void Prim(graph &g){
int min_cost = 0;
int lowcost[NUM]; //当前最短距离
int closest[NUM]; //顶点的相邻顶点(closest[i]则为i的邻接点)
int s[NUM]; //标志访问节点
for(int i = 1;i<=g.v;i++){
closest[i] = 1; //初始置各顶点得邻接点为1
lowcost[i] = g.arac[1][i]; //初始置各顶点的最短距离为1到顶点的距离
s[i] = 0;
}
for(int i = 1;i<g.v;i++){
int min = INIT; //min初始化无穷大
int j = 1;
for(int k = 2;k<=g.v;k++){
if(lowcost[k]<min&&!s[k]){ //找出与源点相连,且权值最小的顶点
min = lowcost[k]; j = k;
}
else{
;
}
}
min_cost+=min;
cout<<closest[j]<<"->"<<j<<endl; //输出符合最小生成树的顶点
s[j] = 1; //已访问顶点置1
for(int t = 2;t<=g.v;t++){
if(g.arac[j][t]<lowcost[t]&&!s[t]){ //从新添加的顶点j出发,将与j相邻的顶点间的权值
//与上一顶点的相邻顶点间的权值进行比较。选出最小权值和相应顶点.
lowcost[t] = g.arac[j][t];
closest[t] = j;
}
}
}
cout<<"最小生成树得最短路径为:"<<min_cost<<endl;
}
int main(){
graph g;
Create_Graph(g);
cout<<"最小生成树的构建路径为:"<<endl;
Prim(g);
return 0;
}
/**
1 2 6
1 3 1
1 4 5
2 3 5
2 5 3
3 4 5
3 5 6
3 6 4
4 6 2
5 6 6
*/