并查集,顾名思义合并查找。时间一长有点记不清怎么写了,现在赶紧写下记录一下。。。。。
典型例题有:hdu1232 ,poj 2524 ,poj 1182, hdu 1213.
主要函数就两个find,union。
find用来查找他的祖先,union用来合并。
int finds(int x)//查找他的祖先
{
int r=x;
while(vis[r]!=r)
r=vis[r];
return r;
}
void unon(int a,int b)//合并祖先
{
int aa=finds(a);
int bb=finds(b);
if(aa!=bb)
vis[aa]=bb;
}
最重要的是先定义好祖先数组,让每个数字等于他自身,即自己是自己的祖先,开始根据所给关系查找,拿hdu1232举例:
#include<bits/stdc++.h>
using namespace std;
int vis[1005];
int finds(int x)//如果自己不是自己,返回自己的祖先值
{
int r=x;
while(vis[r]!=r)
r=vis[r];
return r;
}
void union(int a,int b)
{
int aa=finds(a);//查找每个数字的祖先
int bb=finds(b);
if(aa!=bb)
vis[aa]=bb;//祖先不同进行合并
}
int main()
{
int n,m;
while(~scanf("%d%d",&n,&m))
{
if(n==0)
break;
int a,b;
for(int i=1;i<=n;i++)
vis[i]=i;//将其自己赋值自己,开始自己是自己祖先
for(int i=0;i<m;i++)
{
scanf("%d%d",&a,&b);//输入关系进行查找
union(a,b);
}
int sum=0;
for(int i=1;i<=n;i++)
{
if(vis[i]==i)//通过合并将所有关系打乱,只有vis[i]=I的表明自己是一个集合,要是其他集合的人,自身祖先数组会改变!!!!
sum++;
}
cout<<sum-1<<endl;//题目求的是还剩几条
}
return 0;
}
例如测试数据
4 2
1 3
4 3
vis数组关系:
最后重要一点:要判断有几个集合通过循环查找自己与vis数组相同的,即vis[i]=i;有几个相等的就有几个集合,如果他和其他集合有关系,自身祖先数组vis会改变,不会是自己的!!!!!
再根据题意判断要求的结果!!!