1. 程式人生 > >Prim輸出無向圖中所有的最小生成樹

Prim輸出無向圖中所有的最小生成樹

思路:
給出n個頂點m條邊。一棵最小生成樹中有n-1條邊,所以在m條邊中選n-1條邊判斷能否構成最小生成樹,如果能則直接輸出。
判斷是否能構成最小生成樹的條件是 當前的n-1條邊的權值的和是否是最小生成樹的權值的和(程式碼裡的ans)。
步驟:
先進行一次prim,只是為了求出MST的權值ans。
再對m條邊進行深搜,當選中n-1條邊時判斷是否能構成最小生成樹。

程式碼:

#include<stdio.h>
#include<string.h>
#include<string>
#include<algorithm>
#include<map> 
#include<vector> #define INF 0x3f3f3f3f #define Max 1010 using namespace std; int n,m,tt,ans;//頂點個數 邊的個數 輸出計數 MST的權值 struct edge { int u,v,w; } Q[Max]; int mp[Max][Max],dis[Max],book[Max]; int used[Max][Max],pre[Max]; int out[Max],in[Max]; void print(int n) // 輸出最小生成樹函式;
{ printf("第%d棵最小生成樹:\n",tt++); for(int j=0;j<n;j++) for(int i=0;i<=j;i++) { if(i==j) printf("%d - %d:%d\n",out[i],in[i],mp[out[i]][in[i]]); else printf("%d - %d:%d,",out[i],in[i],mp[out[i]][in[i]]); } } int prim(int u,int
s)//s表示狀態 { memset(book,0,sizeof(book)); int sum=0,nn=0; for(int i=1;i<=n;i++) { //初始為1到能到的頂點的距離 if(used[u][i]==s) dis[i]=mp[u][i];//在n-1條邊中起點為1的邊 else dis[i]=INF;//其餘的邊 pre[i]=u; } book[u]=1; for(int i=1;i<=n-1;i++) { int minn=INF; for(int j=1;j<=n;j++) { if(dis[j]<minn&&book[j]==0) { minn=dis[j]; u=j; } } if(minn==INF) return -1; book[u]=1; sum+=dis[u]; out[nn]=pre[u]; in[nn++]=u; for(int k=1;k<=n;k++) { if(mp[u][k]<dis[k]&&book[k]==0&&used[u][k]==s) { dis[k]=mp[u][k]; pre[k]=u; } } } //if(nn==n-1) // prf(nn); return sum; } void init() // 初始化 { memset(used,0,sizeof(used)); for(int i=0;i<=n;i++) { for(int j=0;j<=n;j++) { if(i==j) mp[i][j]=0; else mp[i][j]=mp[j][i]=INF; } } } void dfs(int top,int x,int sum)//當前選中的邊,當前樹中有幾條邊和權值 { if(sum>ans||x>=n) return; if(top==m) { if(x==n-1&&sum==ans) { int cnt=prim(1,1); if(cnt==ans) print(n-1);//如果權值相同則輸出n-1條邊 } return; } edge tt=Q[top]; used[tt.u][tt.v]=used[tt.v][tt.u]=1;//選中這條邊 dfs(top+1,x+1,sum+tt.w); used[tt.u][tt.v]=used[tt.v][tt.u]=0;//取消標記 dfs(top+1,x,sum);//不選這條邊 } int main() { while(~scanf("%d%d",&n,&m)) { init(); int u,v,w; for(int i=0; i<m; i++) { scanf("%d%d%d",&u,&v,&w); if(w<mp[u][v]) mp[u][v]=mp[v][u]=w; Q[i].u=u; Q[i].v=v; Q[i].w=w; } tt=1; ans=prim(1,0); if(ans==-1) printf("沒有最小生成樹,請重新輸入:\n"); else dfs(0,0,0); } return 0; } /* 思路: 第一次prim只是為了求最小生成樹的權值用來剪枝(期間沒有更新used) 深搜:在m條邊中選n-1條邊判斷是否能構成最小生成樹 */