并查集,顾名思义,分为并和查两个操作。
如何并?什么时候应该并?
首先,如果它们的根节点相同那么就不需要再并了,如果根节点不是同一个,那么将根节点连起来。代码如下:
union(u,v)
{
u = find(u);
v = find(v);
if(u != v)
fa[u] = v;
}
上面的代码有一个find()函数,用来查找根节点,这便是查了。记得压缩一下路径,也就是找到后直接将该节点连成根节点的子节点,下次就不用走那么远啦。
int find(int a)
{
return father[a] == a?a:father[a] = find(father[a]);
}
先说hdu1272,无向图,判无环就行,一定只有一个点是根。
//无向图,是否是最小生成树
#include<stdio.h>
#define max 100010
int father[max],visit[max],flag;
int find(int a)
{
//while(a!=father[a])a=father[a];
//return a;
return father[a]==a?a:father[a]=find(father[a]);
}
void Union(int u,int v)
{
u=find(u);
v=find(v);
if(u!=v)
{
father[u]=v;
}
else flag=0;
}
int main()
{
int a,b,root;
while(scanf("%d%d",&a,&b)!=EOF)
{
if(a==-1&&b==-1)break;
if(a==0&&b==0){printf("Yes\n");continue;}
for(int i=1;i<max;i++)
{
father[i]=i;
visit[i]=0;
}
flag=1;
Union(a,b);
visit[a]=visit[b]=1;
while(scanf("%d%d",&a,&b)!=EOF)
{
if(a==0&&b==0)break;
Union(a,b);
visit[a]=visit[b]=1;
}
//无环
root=0;
for(int i=1;i<max;i++)
{
if(visit[i]&&father[i]==i)root++;
if(root>1)flag=0;
}
if(flag)printf("Yes\n");
else printf("No\n");
}
return 0;
}
再进一步,看看1325,有向图,根据题意,有三个判断条件:无环,入度为1,不是森林。这道题我不知道自己开始的代码究竟跪哪了
#include<stdio.h>
#define max 1000
int father[max],visit[max],flag,in[max];
void init()
{
//初始化
for(int i=1;i<max;i++)
{
father[i]=i;
visit[i]=0;
in[i]=0;
}
flag=1;
}
int find(int a)
{
return a==father[a]?a:father[a]=find(father[a]);
}
void Union(int u,int v)
{
u=find(u);
v=find(v);
if(u!=v)father[u]=v;
else flag=0;
}
int main()
{
int a,b,k=1,t;
init();
while(scanf("%d%d",&a,&b)){
if(a<0&&b<0)break;
if(a==0&&b==0){
if(flag){
for(int i=1;i<max;i++){
if(visit[i]){
t=find(i);
break;
}
}
for(int i=1;i<max;i++){
//入度
if(in[i]>1){flag=0;break;}
if(visit[i]&&t!=find(i)){flag=0;break;}
}
}
if(flag)printf("Case %d is a tree.\n",k++);
else printf("Case %d is not a tree.\n",k++);
init();
}else{
Union(a,b);
if(!flag)continue;
visit[a]=visit[b]=1;
in[b]++;
}
}
}
//连通分量数目-1即还需要增加多少边
#include<stdio.h>
#define max 1010
int father[max],cnt;
int find(int a)
{
return father[a]==a?a:father[a]=find(father[a]);
}
void Union(int u,int v)
{
u=find(u);
v=find(v);
if(u!=v)father[u]=v;
}
int main()
{
int n,m,a,b;
while(scanf("%d",&n)!=EOF)
{
if(n==0)break;
scanf("%d",&m);
cnt=0;
for(int i=1;i<=n;i++)
father[i]=i;
for(int i=0;i<m;i++)
{
scanf("%d%d",&a,&b);
Union(a,b);
}
for(int i=1;i<=n;i++)
{
if(father[i]==i)cnt++;
}
printf("%d\n",cnt-1);
}
return 0;
}