import java.io.FileNotFoundException;
import java.util.Scanner;
public class Main2 {
static Node[] nodes;
static int count = 0;// 信仰个数
public static void main(String s[]) throws FileNotFoundException {
int count_i = 1;
Scanner cin = new Scanner(System.in);
int n = cin.nextInt();
int m = cin.nextInt();
while (true) {
if (n != 0 && m != 0) {
count = n;
// 初始化n个节点
int nodes_count = n + 1;
nodes = new Node[nodes_count];
for (int i = 0; i < nodes_count; i++) {
nodes[i] = new Node();
}
for (int i = 0; i < nodes_count; i++) {
nodes[i].father = i;// 初始化的时候,父亲是本身
nodes[i].children = 0;
}
while (m > 0) {
// 得到两个学生
int a = cin.nextInt();
int b = cin.nextInt();
int afather = nodes[a].father;// a的父亲
int bfather = nodes[b].father;// b的父亲
union(afather, bfather);
m--;
}
System.out.println("Case " + count_i + ": " + count);
count = 0;// count重新归0
n = cin.nextInt();
m = cin.nextInt();
count_i++;// case数加1
} else {
break;
}
}
}
/**
* 递归查找x的父亲
*
* @param x
* @return
*/
public static int find(int x) {
if (x == nodes[x].father)
return x;
else {
return find(nodes[x].father);
}
}
/**
* 压缩路径
* @param x
* @return
*/
public static int find3(int x) {
int t = x;
// 找到x的父亲。这个循环关键在于理解并查集中,根节点的父亲是自身。
while (x != nodes[x].father) {
x = nodes[x].father;
}
while (t != x) {
int temp = nodes[t].father;
nodes[t].father = x;
nodes[t].children = 0;
t = temp;
}
return x;
}
/**
* 把a和b所在的集合合并
*
* @param a
* @param b
*/
public static void union(int x1, int x2) {
int parent1 = find3(x1);
int parent2 = find3(x2);
if (parent1 != parent2) {
count--;
if (nodes[parent1].children < nodes[parent2].children) {
nodes[parent1].father = parent2;
nodes[x2].children = nodes[x1].children + 1
+ nodes[x2].children;
} else {
nodes[parent2].father = parent1;
nodes[x1].children = nodes[x1].children + nodes[x2].children
+ 1;
}
}
}
}
class Node {
int father;
int children;
public int getChildren() {
return children;
}
public void setChildren(int children) {
this.children = children;
}
public int getFather() {
return father;
}
public void setFather(int father) {
this.father = father;
}
}
想起来龙哥之前做过这个题目,今天没事拿出来再看看。find函数有一个实现是递归查找父亲,第二个是传说中的路径压缩。
Node中设置一个father和一个children属性,分别表示当前节点的父亲节点和当前节点有多少个儿子节点。
在合并操作的时候,根据儿子节点的个数,选择将节点少的树合并到节点多的树中。