http://acm.hziee.edu.cn/showproblem.php?pid=1272
并查集的典型用法。
如果只是单纯的找根和压缩路径,用递归的方法会栈溢出,用两个循环则会超时。
贴上乐乐的程序。他用负数表示树的根,而负数的大小就是树的深度。在两棵树合并是,先比较它们深度,把深度小的那一棵树直接连到深度大的根上,实现相对平衡。
#include "stdio.h"
#include "memory.h"
int bin[100004];
int point,edge;
int getit(int x)
{
if(bin[x] <= 0)
return x;
else return bin[x]=getit(bin[x]);
}
int join(int a,int b)
{
int fa,fb;
fa=getit(a);
fb=getit(b);
if(fa==fb)
return -1;
edge++;
if(bin[fa]==0 && bin[fb]==0)
{
point+=2;
bin[fa]=-1;
bin[fb]=fa;
}
else if(bin[fa]==0 && bin[fb]!=0)
{
bin[fa]=fb;
point++;
}
else if(bin[fa]!=0 && bin[fb]==0)
{
bin[fb]=fa;
point++;
}
else
{
if(bin[fa]==bin[fb])
{
bin[fa]=fb;
bin[fb]--;
}
else if(bin[fa]<bin[fb])
{
bin[fb]=fa;
}
else
{
bin[fa]=fb;
}
}
return 1;
}
int main()
{
int a,b;
int flag;
while(scanf("%d %d",&a,&b),a!=-1)
{
if(a==0 && b==0)
{
printf("Yes\n");
continue;
}
memset(bin,0,sizeof(bin));
point=0;
edge=0;
join(a,b);
flag=1;
while(scanf("%d %d",&a,&b),a||b)
{
if(flag==1)
{
if(join(a,b)==-1)
{
flag=0;
}
}
}
if(flag==0 || point!=edge+1)
printf("No\n");
else printf("Yes\n");
}
return 0;
}