一般最小生成樹算法分成兩種算法:
一個是克魯斯卡爾算法:這個算法的思想是利用貪心的思想,對每條邊的權值先排個序,然后每次選取當前最小的邊,判斷一下這條邊的點是否已經被選過了,也就是已經在樹內了,一般是用並查集判斷兩個點是否已經聯通了;
另一個算法是普里姆算法:這個算法長的賊像迪傑斯塔拉算法,首先選取一個點進入集合內,然后找這個點連接的點里面權值最小的點,然后每次在選取與集合內任意一點連接的點的邊的權值最小的那個(這個操作可以在松弛那里修改一下,這也是和迪傑斯塔拉算法最大的不同,你每次選取一個點后,把這個點能達到的點的那條邊的權值修改一下,而不是像迪傑斯塔拉算法那樣,松弛單點權值);
克魯斯卡爾代碼:
#include<iostream> #include<algorithm> #define maxn 5005 using namespace std; struct Node { int x; int y; int w; }node[maxn]; int cmp(Node x,Node y) { return x.w<y.w; } int fa[maxn]; int findfa(int x) { if(fa[x]==x) return x; else return findfa(fa[x]); } int join(int u,int v) { int t1,t2; t1=findfa(u); t2=findfa(v); if(t1!=t2) { fa[t2]=t1; return 1; } else return 0; } int main() { int i,j; int sum; int ans; int n,m; sum=0;ans=0; cin>>n>>m; for(i=1;i<=m;i++) cin>>node[i].x>>node[i].y>>node[i].w; sort(node+1,node+1+m,cmp); for(i=1;i<=n;i++) fa[i]=i; for(i=1;i<=m;i++) { if(join(node[i].x,node[i].y)) { sum++; ans+=node[i].w; } if(sum==n-1) break; } cout<<ans<<endl; return 0; } 普里姆算法: #include<iostream> #include<algorithm> #include<cstring> #include<cstdio> #define inf 0x3f3f3f using namespace std; int Map[1005][1005]; int dist[1005]; int visit[1005]; int n,m; int prime(int x) { int temp; int lowcast; int sum=0; memset(visit,0,sizeof(visit)); for(int i=1;i<=n;i++) dist[i]=Map[x][i]; visit[x]=1; for(int i=1;i<=n-1;i++) { lowcast=inf; for(int j=1;j<=n;j++) if(!visit[j]&&dist[j]<lowcast) { lowcast=dist[j]; temp=j; } visit[temp]=1; sum+=lowcast; for(int j=1;j<=n;j++) { if(!visit[j]&&dist[j]>Map[temp][j]) dist[j]=Map[temp][j]; } } return sum; } int main() { int y,x,w,z; scanf("%d%d",&n,&m); for(int i=1;i<=n;i++) { for(int j=1;j<=n;j++) { if(i==j) Map[i][j]=0; else Map[i][j]=inf; } } memset(dist,inf,sizeof(dist)); for(int i=1;i<=m;i++) { scanf("%d%d%d",&x,&y,&w); Map[x][y]=w; Map[y][x]=w; } z=prime(1); printf("%d\n",z); return 0; }
