prime算法的精髓在于:
每次选取一条边。
该边满足:1、一端已选,一端未选;2、该边权值最小。
直到选取n-1条边或选取n个顶点算法结束,求出MST或者判断出不存在MST。
代码设计:
1、利用两个集合存放已选顶点和未选顶点
(choosed[]存放已选顶点,unchoosed[]存放未选顶点)
2、每次选取的边都是一端在choosed[]中,另一端在unchoosed[]中的权值最小的边
3、利用STL中vector可以方便的实现图的临界表存储
4、记录组成MST的每条边很方便,只要在选取到一条满足条件的边时记录下起点、终点、权值即可
代码:
#include<iostream> #include<cstring> #include<vector> using namespace std; const int maxn=101; //顶点数 const int INF=0x7fffffff; struct edge //边 { int to; //到达的点 int cost; //边的花费 bool flag; //是否入选 }; int choosed[maxn]; //已选顶点 int unchoosed[maxn]; //未选顶点 int nodeNum,edgeNum,MST; //顶点数、边数、最小生成树 bool choose[maxn]; //顶点是否已选 vector<edge> myV[maxn]; //图的邻接表 /* //这是无向图有重复边的建图,取重复边中最小的边存储 bool exist(int from,int to,int cost) { bool existFlag=false,smallFlag=false; for(int i=0;i<myV[from].size();i++) { if(myV[from][i].to==to) { existFlag=true; if(myV[from][i].cost>cost) { smallFlag=true; myV[from][i].cost=cost; break; } } } if(smallFlag) { for(int j=0;j<myV[to].size();j++) { if(myV[to][j].to==from) { myV[to][j].cost=cost; break; } } } if(existFlag) return true; return false; } void storeMap() //邻接表存图 { for(int j=0;j<maxn;j++) //清空 { myV[j].clear(); } memset(choose,false,sizeof(choose)); //标志图的各个点是否被选,不能重复 int from,to,cost,num=0; //从from到to花费cost的边 for(int i=0;i<edgeNum;i++) { scanf("%d%d%d",&from,&to,&cost); //把图上的所有点不重复的放到unchoosed[]表中 if(!choose[from]) { unchoosed[num++]=from; choose[from]=true; } if(!choose[to]) { unchoosed[num++]=to; choose[to]=true; } if(!exist(from,to,cost)) //图中存在重复边的处理 { edge tmp; tmp.flag=false; tmp.cost=cost; //无向图 tmp.to=to; myV[from].push_back(tmp); tmp.to=from; myV[to].push_back(tmp); } } } */ //无向图,无重复边的建图 void storeMap() //邻接表存图 { for(int j=0;j<maxn;j++) //清空 { myV[j].clear(); } memset(choose,false,sizeof(choose)); //标志图的各个点是否被选,不能重复 int from,to,cost,num=0; //从from到to花费cost的边 for(int i=0;i<edgeNum;i++) { scanf("%d%d%d",&from,&to,&cost); //把图上的所有点不重复的放到unchoosed[]表中 if(!choose[from]) { unchoosed[num++]=from; choose[from]=true; } if(!choose[to]) { unchoosed[num++]=to; choose[to]=true; } edge tmp; tmp.flag=false; tmp.cost=cost; //无向图 tmp.to=to; myV[from].push_back(tmp); tmp.to=from; myV[to].push_back(tmp); } } void prime() //prime算法 { //初始化一些信息 MST=0; memset(choose,false,sizeof(choose)); choosed[0]=unchoosed[0]; choose[unchoosed[0]]=true; int choosedNum=1,from,to,cost,index; while(choosedNum<nodeNum) { cost=INF; //从所有已选顶点中,找一条费用最小,且没选的边 for(int i=0;i<choosedNum;i++) { for(int j=0;j<myV[choosed[i]].size();j++) { edge tmp=myV[choosed[i]][j]; if(!choose[tmp.to] && !tmp.flag && tmp.cost<cost) { from=choosed[i]; to=tmp.to; cost=tmp.cost; index=j; } } } myV[from][index].flag=true; //将找到的边标志为已选 //无向图,从from->to的边已选,那么从to->from的边也已选 for(int k=0;k<myV[to].size();k++) { if(myV[to][k].to==from) { myV[to][k].flag=true; break; } } choosed[choosedNum++]=to; //将选择的顶点放到已选点集合中 choose[to]=true; MST+=cost; //最小生成树费用增加 } printf("%d\n",MST); } int main() { while(scanf("%d%d",&nodeNum,&edgeNum)==2) //输入图的点数、边数 { storeMap(); prime(); } system("pause"); return 0; }
测试实例:
1、图形:
2、输入及结果:
问题:
如何利用prime算法求解有向图的MST?
先留在这吧。。。