Prim算法---最小生成樹
阿新 • • 發佈:2017-09-02
lld size stream queue truct type 個數 c89 tro
最小生成樹的Prim算法也是貪心算法的一大經典應用。Prim算法的特點是時刻維護一棵樹,算法不斷加邊,加的過程始終是一棵樹。
Prim算法過程:
一條邊一條邊地加, 維護一棵樹。
初始 E = {}空集合, V = {任意節點}
循環(n – 1)次,每次選擇一條邊(v1,v2), 滿足:v1屬於V , v2不屬於V。且(v1,v2)權值最小。
E = E + (v1,v2)
V = V + v2
最終E中的邊是一棵最小生成樹, V包含了全部節點。 以下圖為例介紹Prim算法的執行過程。 Prim算法的過程從A開始 V = {A}, E = {}
選中邊AF , V = {A, F}, E = {(A,F)}
選中邊FB, V = {A, F, B}, E = {(A,F), (F,B)}
選中邊BD, V = {A, B, F, D}, E = {(A,F), (F,B), (B,D)}
選中邊DE, V = {A, B, F, D, E}, E = {(A,F), (F,B), (B,D), (D,E)}
選中邊BC, V = {A, B, F, D, E, c}, E = {(A,F), (F,B), (B,D), (D,E), (B,C)}, 算法結束。 最後,我們來提供輸入輸出數據,由你來寫一段程序,實現這個算法,只有寫出了正確的程序,才能繼續後面的課程。 輸入
輸出
輸出示例
Prim算法過程:
一條邊一條邊地加, 維護一棵樹。
初始 E = {}空集合, V = {任意節點}
循環(n – 1)次,每次選擇一條邊(v1,v2), 滿足:v1屬於V , v2不屬於V。且(v1,v2)權值最小。
E = E + (v1,v2)
V = V + v2
最終E中的邊是一棵最小生成樹, V包含了全部節點。 以下圖為例介紹Prim算法的執行過程。 Prim算法的過程從A開始 V = {A}, E = {}
選中邊AF , V = {A, F}, E = {(A,F)}
選中邊FB, V = {A, F, B}, E = {(A,F), (F,B)}
選中邊BD, V = {A, B, F, D}, E = {(A,F), (F,B), (B,D)}
選中邊DE, V = {A, B, F, D, E}, E = {(A,F), (F,B), (B,D), (D,E)}
選中邊BC, V = {A, B, F, D, E, c}, E = {(A,F), (F,B), (B,D), (D,E), (B,C)}, 算法結束。 最後,我們來提供輸入輸出數據,由你來寫一段程序,實現這個算法,只有寫出了正確的程序,才能繼續後面的課程。 輸入
第1行:2個數N,M中間用空格分隔,N為點的數量,M為邊的數量。(2 <= N <= 1000, 1 <= M <= 50000) 第2 - M + 1行:每行3個數S E W,分別表示M條邊的2個頂點及權值。(1 <= S, E <= N,1 <= W <= 10000)
輸出最小生成樹的所有邊的權值之和。輸入示例
9 14 1 2 4 2 3 8 3 4 7 4 5 9 5 6 10 6 7 2 7 8 1 8 9 7 2 8 11 3 9 2 7 9 6 3 6 4 4 6 14 1 8 8
輸出示例
37請選取你熟悉的語言,並在下面的代碼框中完成你的程序,註意數據範圍,最終結果會造成Int32溢出,這樣會輸出錯誤的答案。 不同語言如何處理輸入輸出,請查看下面的語言說明。 簡單的最小生成樹,自己寫的代碼一直過不了 AC代碼(prim算法)
#include<iostream> #include<cstdio> #include<map> #include<cstring> #include<string> #include<algorithm> #include<queue> #include<vector> #include<stack> #include<cstdlib> #include<cctype> #include<cstring> #include<cmath> using namespace std; const int inf=0x3f3f3f3f; int G[1001][1001];//鄰接矩陣 int vis[1001],lowc[1001]; int prim(int G[][1001],int n){ int i,j,p,minc,res=0; memset(vis,0,sizeof(vis)); vis[1]=1;//從1開始訪問 for(i=2;i<=n;i++) lowc[i]=G[1][i]; for(i=2;i<=n;i++){ minc=inf; p=-1; for(j=1;j<=n;j++){ if(vis[j]==0&&lowc[j]<minc){ minc=lowc[j]; p=j; } } //cout<<minc<<endl; if(inf==minc) return -1;//原圖不聯通 res+=minc; vis[p]=1; for(j=1;j<=n;j++){//更新lowc[] if(vis[j]==0&&lowc[j]>G[p][j]){ lowc[j]=G[p][j]; } } } return res; } int main() { int n,m; while(cin>>n>>m){ int x,y,w; memset(G,inf,sizeof(G));//首先記錄所有邊的權為inf for(int i=1;i<=m;i++){ cin>>x>>y>>w; G[x][y]=G[y][x]=w; //cout<<G[x][y]<<endl; } //int res=prim(n); cout<<prim(G,n)<<endl; } return 0; }
自己寫的代碼不知道錯哪了(kruskal算法)
#include<stdio.h> #include<string.h> #include<algorithm> using namespace std; struct tr { int s,e,w; }p[50000+10]; bool cmp(tr x, tr y) { return x.w < y.w; } int n,m; int f[1000+10]; int i,j; long long ans; int find(int x) //找父親 { int r = x; while(f[r] != r) r = f[r]; return r; int i = x, j; while(i != r) { j = f[i]; f[i] = r; r = j; } } void join(int x, int y) { int fx = find(x); int fy = find(y); if(fx != fy) f[fx] = fy; } int kruskal() { sort(p, p+m, cmp); for(i=0; i<n; i++) { f[i] == i;//初始化 父親節點 } for(i=0; i<n; i++) { if(find(p[i].s) != find(p[i].e)) { join(p[i].e, p[i].s); ans += p[i].w; } } return ans; } int main() { ans=0; scanf("%d %d",&n,&m); for(i=0; i<m; i++) { scanf("%d %d %d",&p[i].s, &p[i].e, &p[i].w); } kruskal(); printf("%lld\n",ans); return 0; }
Prim算法---最小生成樹