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
输出包含一个数,即最小生成树的各边的长度之和;
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;
}