/*
POJ 2524
类型:并查集(基础)
题意:就是求已知有m个点,n条边相连,求出连通子图有多少个
思路:新建并查集节点,查找,判断,合并
*/
#include<iostream>
using namespace std;
#define M 50005
int root[M]; //根节点
int flag[M]; //标志的第i个点,是否已经在集合中,0代表在,1代表(可能是根,或者不在)
int rank[M]; //代表,0代表不是根节点,其他代表1-n位,有森林中有多少棵树
void Inital(int n) //初始化函数
{
int i;
for( i = 1 ; i <= n ; i++ )
{
root[i] = i ; //默认值
flag[i] = 1;
rank[i] = 0;
}
}//Inital
int Find( int index ) //查找函数,递归
{
if( root[index] == index ) //出口位置
return index;
index = Find( root[index] );
return index;
}
void Union( int x,int y ) //合并
{
x = Find(x);
y = Find(y);
if( x == y ) //如果是一个根节点,则不用进行加入
return ;
if( rank[x] == rank[y] ) //如果同为单节点、树、森林,则进行合并
{
rank[x]++;
root[y] = x;
flag[y] = 0;
}
else if( rank[x] > rank[y] ) //rank[]的值大小,代表那个的节点多,而合并的原则是:多的合并少的
{
root[y] = x;
flag[y] = 0;
}
else
{
root[x] = y;
flag[x] = 0;
}
}//Union
int main()
{
int i;
int n,m;
int sum;
int x,y;
cin >> m >> n;
int num=1;
while( m + n )
{
sum =0 ;
if( n == 0 )
cout << "Case " << num <<": " << m << endl;
else
{
Inital(m);
for( i = 1 ; i <= n ; i++ )
{
cin >> x >> y;
Union(x,y);
}
for( i = 1 ; i <= m; i ++ ) //计数求得结果
sum += flag[i];
cout << "Case " << num <<": " << sum << endl;
}
cin >> m >> n;
num++;
}//while
return 0;
}