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?
先留在這吧。。。