并查集讲解: http://blog.csdn.net/zark721/article/details/77816406
原题:http://acm.hdu.edu.cn/showproblem.php?pid=1232
#include<cstdio>
int pre[1010];//记录每一个节点的跟节点
int find(int x)//寻找x的根节点
{
int r=x;
while(pre[r]!=r)//找父亲
{
r=pre[r];
}
//压缩,修改自己和上级的pre,全部直接变成老大
int j=x,k;
while(j!=r)
{
k=pre[j];//保存上级
pre[j]=r;//自己的上级变成老大
j=k;
}
return r;
}
void join(int x,int y)//合并函数
{
int fx=find(x);
int fy=find(y);
if(fx!=fy)//如果我们两个的老大不一样
{
pre[fx]=fy;//结盟
}
}
int n,m;
void init()//初始化
{
for(int i=1;i<=n;i++)
{
pre[i]=i;
}
}
int main()
{
scanf("%d",&n);
while(n!=0)
{
scanf("%d",&m);
init();//初始化
for(int i=0;i<m;i++)
{
int p1,p2;
scanf("%d %d",&p1,&p2);
join(p1,p2);
}
int ans=0;
for(int i=1;i<=n;i++)
{
if(pre[i]==i)
{
ans++;
}
}
printf("%d\n",ans-1);
scanf("%d",&n);
}
return 0;
}