这篇文章是写给克鲁斯算法的并查集,理解的。以前写的啊哈上面的并查集,然后感觉和那个克鲁斯算法的并查集,不一样。(其实本质是一样的,但是啊哈用了递归来写,这个直接写在一个函数上面),因为正在学克鲁斯算法,所以这篇文章会一直更新。
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
int pre[1010],n,m;
void chushihua()//数组的初始化。
{
for(int i=0; i<=n; i++)
pre[i]=i;
return ;
}
int find1(int x)//这里就是不一样地方,在这个函数当中用while循环去找祖宗,而不是用递归。
{
int r=x;
while (pre[r]!=r)
r=pre[r];
int i=x,j ;
while(i!=r)
{
j=pre[i];
pre[i]= r ;
i=j;
}
return r ;
}
void join(int x,int y)//这个是合并,也是一个关键,如果两个人的祖宗不一样,通过这个集合合并成一个集合。
{
int fx=find1(x);
int fy=find1(y);
if(fx!=fy)
pre[fx ]=fy;
}
int main()
{
while(~scanf("%d%d",&n,&m))
{
chushihua();
for(int i=0; i<m; i++)
{
int x,y;
scanf("%d%d",&x,&y);
join(x,y);
}
int ans=0;
for(int i=1; i<=n; i++)
if(pre[i]==i)
ans++;
printf("%d\n",ans);
}
return 0;
}
下面是克鲁斯卡尔的代码,尤其压缩路径很厉害
#include<stdio.h>
#include<string.h>
#include<algorithm>
using namespace std;
#define bian 1010
#define dian 1010
struct node
{
int x,y,w;
}b[bian];
int parent[dian];
int n,m;
void cn()//并查集的初始化
{
for(int i=0;i<=n;i++)
parent[i]=-1;
}
int find(int x)
{
int s;
for(s=x;parent[s]>=0;s=parent[s])
;
while(s!=x)//克鲁斯卡尔的压缩路径,也是并查集的压缩路径方法
{
int tmp=parent[x];
parent[x]=s;
x=tmp;
}
return s;
}
int hebing(int r1,int r2)
{
int tx=find(r1);
int ty=find(r2);
int tmp=parent[tx]+parent[ty];//因为还是最小生成树,于是需要权值的介入
if(parent[tx]>parent[ty])
{
parent[tx]=ty;
parent[ty]=tmp;
}
else
{
parent[ty]=tx;
parent[tx]=tmp;
}
}
int cmp(node a,node b)
{
return a.w<b.w;
}
void kruskal()//其实克鲁斯卡尔很好理解
{
int sumweight=0;
int num=0;
int u,v;
cn();
for(int i=0;i<m;i++)
{
u=b[i].x;
v=b[i].y;
if(find(u)!=find(v))
{
printf("%d %d %d\n",u,v,b[i].w);
num++;
sumweight+=b[i].w;
hebing(u,v);
}
if(num>=n-1)
break;
}
printf("%d\n",sumweight);
}
int main()
{
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++)
{
int x,y,w;
scanf("%d%d%d",&x,&y,&w);
b[i].x=x;
b[i].y=y;
b[i].w=w;
}
sort(b,b+m,cmp);
kruskal();
}