【模板】最小生成树(prime、kruscal、prim堆优化)

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
",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
",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
",ans);
    else puts("orz");
}
原文地址:https://www.cnblogs.com/wuwendongxi/p/13549961.html