/*
问题:并查集,定义数组,用双亲表示法表示各棵树。畅通工程
输入:城镇数目N(<1000)和道路数目M,城镇从1到N开始编号,N=0时输入结束
输入:
4 2
1 3
4 3
3 3
1 2
1 3
2 3
5 2
3 5
999 0
0
输出:
1
0
2
998
关键:
1 输入m要单独输入,不能写成同时要求输入2个数,这样你输入一个数就不起作用了
2 在路径压缩中 寻找的是x的父节点的根节点 int iTemp = findRoot(Tree[x]);
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int Tree[1024];
/*
int findRoot(int x)
{
if(-1==x)
{
return x;
}
else
{
return findRoot(Tree[x]);//Tree[x]表示x的双亲节点编号
}
}
*/
//路径压缩:在查找某个特定节点的根节点的同时将其与根节点之间的所有的节点都直接指向根节点
int findRoot(int x)
{
if(-1==Tree[x])
{
return x;
}
//如果不是根节点
else
{
//int iTemp = findRoot(x);//temp最终拿到的是根节点的值,易错,这里查找的应该是x的父节点的根节点
int iTemp = findRoot(Tree[x]);
Tree[x] = iTemp;//设置当前节点的双亲节点为查找返回的根节点编号
return iTemp;
}
}
/*
int findRoot(int x,bool i)
{
int iTemp = x;
while(Tree[x]!=-1)
{
x = Tree[x];
}
int iRoot = x;
while(Tree[iTemp]!=-1)
{
int iParent = Tree[iTemp];//保留原始父节点
Tree[iTemp] = iRoot;//设置新的父节点
iTemp = iParent;//更新搜索节点
}
return iRoot;
}
*/
int main(int argc,char* argv)
{
//n表示城镇数目,m表示道路数目
int n,m;
int iResArr[100];
int iSize = 0;
int i;
while(EOF!=scanf("%d",&n) && 0!=n)
{
scanf("%d",&m);//输入m要单独输入
//初始,要设置城镇中每个父节点为根节点
for(i = 1 ; i <= n ; i++)
{
Tree[i] = -1;
}
int iRoadName1,iRoadName2;
//对M组输入进行归并
//for(i = 1 ; i <= n ; i++)
for(i = 1 ; i <= m; i++)
{
scanf("%d %d",&iRoadName1,&iRoadName2);
int iRoot1 = findRoot(iRoadName1);
int iRoot2 = findRoot(iRoadName2);
if(iRoot1!=iRoot2)
{
Tree[iRoot1] = iRoot2;
}
}
//计算独立的并查集
int iTotalRoad = 0;
for(int j = 1 ; j <= n ; j++)
{
if(Tree[j]==-1)
{
iTotalRoad++;
}
}
//printf("%d",iTotalRoad-1);
iResArr[iSize++] = iTotalRoad - 1;
}
for(int k = 0 ; k < iSize ; k++)
{
printf("%d\n",iResArr[k]);
}
system("pause");
getchar();
return 0;
}