1.算法简介
(Prim在稠密图中比Kruskal优,在稀疏图中比Kruskal劣。
·这个算法显然是一个用来找最小生成树的算法
·给一个无向图,这个无向图有N个点,M个边
·首先把边按边权排个序
·然后用这些边从小到大连起来
·如果出现环则不连这条边(用并查集
·连了N-1条边后(即已经构造好最小生成树后)退出
Input
第一行包含两个整数N、M,表示该图共有N个结点和M条无向边。(N<=5000,M<=200000)
接下来M行每行包含三个整数Xi、Yi、Zi,表示有一条长度为Zi的无向边连接结点Xi、Yi
Output
输出包含一个数,即最小生成树的各边的长度之和;
扫描二维码关注公众号,回复:
1062388 查看本文章
2. 问题分段
·构造结构体
struct edge { int u,v,w; } a[M];
·将边排序(手打sort
void swap(int &x,int &y) { int tmp=x; x=y;y=tmp; }
void qsort(int l,int r) { int i=l,j=r,mid=a[(l+r)/2].w; while(i<j) { while(a[i].w<mid) i++; while(mid<a[j].w) j--; if(i<=j) { swap(a[i].u,a[j].u); swap(a[i].v,a[j].v); swap(a[i].w,a[j].w); i++;j--; } } if(i<r) qsort(i,r); if(l<j) qsort(l,j); }
·并查集
1.初始化
for(int i=1;i<=n;i++) f[i]=i;
2.找父节点函数
int getf(int x)
{ if(f[x]==x) { return x; } else { f[x]=getf(f[x]); return f[x]; } }
3.连边
for(int i=1;i<=m;i++)
{
if(getf(a[i].u)!=getf(a[i].v))
{
ans+=a[i].w;
f[getf(a[i].v)]=a[i].u;
cnt++;
if(cnt==n-1) break;
}
}
3.代码实现
#include<iostream> #include<cstdio> using namespace std; const int N=5005; const int M=200005; int f[N]; struct edge { int u,v,w; } a[M]; int n,m,ans; void swap(int &x,int &y) { int tmp=x; x=y;y=tmp; } void qsort(int l,int r) { int i=l,j=r,mid=a[(l+r)/2].w; while(i<j) { while(a[i].w<mid) i++; while(mid<a[j].w) j--; if(i<=j) { swap(a[i].u,a[j].u); swap(a[i].v,a[j].v); swap(a[i].w,a[j].w); i++;j--; } } if(i<r) qsort(i,r); if(l<j) qsort(l,j); } int getf(int x) { if(f[x]==x) { return x; } else { f[x]=getf(f[x]); return f[x]; } } int main() { scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) scanf("%d%d%d",&a[i].u,&a[i].v,&a[i].w); qsort(1,m); for(int i=1;i<=n;i++) f[i]=i; int cnt=0; for(int i=1;i<=m;i++) { if(getf(a[i].u)!=getf(a[i].v)) { ans+=a[i].w; f[getf(a[i].v)]=a[i].u; cnt++; if(cnt==n-1) break; } } printf("%d\n",ans); return 0; }