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");
}