【模板】最小生成樹(prime、kruscal、prim堆優化)
阿新 • • 發佈:2020-08-24
Description
給出一個無向圖,求出最小生成樹,如果該圖不連通,則輸出orz
Input
第一行包含兩個整數N、M,表示該圖共有N個結點和M條無向邊(N<=5000,M<=200000)
接下來M行每行包含三個整數Xi、Yi、Zi,表示有一條長度為Zi的無向邊連線結點Xi、Yi
Output
輸出包含一個數,即最小生成樹的各邊的長度之和;如果該圖不連通則輸出orz
Sample Input
4 5
1 2 2
1 3 2
1 4 3
2 3 4
3 4 3
Sample Output
7
Hint
【資料規模】
對於20%的資料:N<=5,M<=20
對於40%的資料:N<=50,M<=2500
對於70%的資料:N<=500,M<=10000
對於100%的資料:N<=5000,M<=200000
0、題外話
- 關於三種演算法:
- prim常用於稠密圖,kruscal用於稀疏圖,而prim堆優化在稀疏圖中比kruskal跑得慢,在稠密圖中用prim優化有點雞肋。。。
- 演算法講解
1、Prime演算法
#include <iostream> #include <cstdio> #define inf 0x7fffffff using namespace std; int n,m,cnt,head[5005]; struct node{int next,to,w;}e[400005]; void addedge(int x,int y,int z){e[++cnt].to=y,e[cnt].w=z,e[cnt].next=head[x],head[x]=cnt;} int flag[5005],dist[5005]; void prim() { for(int i=1;i<=n;++i) dist[i]=inf; dist[1]=0; int ans=0; for(int i=1;i<=n;++i) { int minn=inf,k=-1; for(int j=1;j<=n;++j) if(dist[j]<minn&&!flag[j]) minn=dist[j],k=j; if(k==-1){puts("orz"); return;} flag[k]=1; ans+=dist[k]; for(int j=head[k];j;j=e[j].next) if(!flag[e[j].to]&&dist[e[j].to]>e[j].w) dist[e[j].to]=e[j].w; } printf("%d\n",ans); } int main() { scanf("%d%d",&n,&m); for(int i=1,x,y,z;i<=m;++i) scanf("%d%d%d",&x,&y,&z),addedge(x,y,z),addedge(y,x,z); prim(); return 0; }
2、Kruskal演算法
#include <iostream> #include <cstdio> #include <algorithm> using namespace std; int n,m,ans,cnt,fa[5005]; struct fdfdfd{int x,y,w;}e[200005]; int getfa(int x){return x==fa[x]?x:fa[x]=getfa(fa[x]);} bool cmp(fdfdfd a,fdfdfd b){return a.w<b.w;} void kruskal() { sort(e+1,e+m+1,cmp); for(int i=1;i<=n;++i) fa[i]=i; for(int i=1;i<=m;++i) { int fx=getfa(e[i].x),fy=getfa(e[i].y); if(fx==fy) continue; fa[fx]=fy; ans+=e[i].w; ++cnt; if(cnt==n-1){printf("%d\n",ans); return;} } puts("orz"); } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;++i) scanf("%d%d%d",&e[i].x,&e[i].y,&e[i].w); kruskal(); return 0; }
3、堆優化prim演算法-STL實現
#include <iostream>
#include <cstdio>
#include <cstring>
#include <queue>
using namespace std;
int cnt,n,m,ans,head[5005],dist[5005],flag[5005];
struct node{int to,w,next;} e[400005];
void addedge(int x,int y,int z){e[++cnt].to=y; e[cnt].w=z; e[cnt].next=head[x]; head[x]=cnt;}
typedef pair <int,int> pii;
priority_queue <pii,vector<pii>,greater<pii> > q;
void prim()
{
memset(dist,0x7f,sizeof(dist)); dist[1]=0;
cnt=0;
q.push(make_pair(0,1));
while(!q.empty()&&cnt<n)
{
int d=q.top().first,u=q.top().second;
q.pop();
if(flag[u]) continue;
++cnt; ans+=d; flag[u]=1;
for(int i=head[u];i;i=e[i].next)
if(e[i].w<dist[e[i].to]) dist[e[i].to]=e[i].w,q.push(make_pair(e[i].w,e[i].to));
}
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=1,x,y,z;i<=m;++i) scanf("%d%d%d",&x,&y,&z),addedge(x,y,z),addedge(y,x,z);
prim();
if(cnt==n) printf("%d\n",ans);
else puts("orz");
}