首先给一个例题:畅通工程
首先给你若干个城镇,这些城镇可以看作是图上的若干个点,道路可以看作点与点之间的连线。这个问题可以转换成,查找图中有几个连通子图,要修建的桥的数量为连通子图数量减一。
并查集是由一个数组和两个函数组成的。数组pre[]中存放着下标i所代表的节点的前导节点,函数join()表示合并两个连通子图,函数find()表示查找某个节点的根节点。
import java.util.Scanner;
public class BingChaJi {
public static int find(int[] pre, int x) {
if (pre[x] == x)
return x;
int r = x;
while (pre[r] != r) { //这一部分是查找根节点。
r = pre[r];
}
int i = x, j;
while (i != r) {//这一部分是压缩路径,将节点的前导节点直接指向根节点
j = pre[i];
pre[i] = r;
i = j;
}
return r;
}
public static void join(int[] pre, int x, int y) {
int root1 = find(pre,x);//注意着里找到的是根节点
int root2 = find(pre,y);
if (root1 != root2)
pre[root1] = root2;//这里也是直接将根节点的前导节点改成了y的根节点
else
return;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while (sc.hasNext()) {
int n = sc.nextInt();
if (n == 0)
break;
int m = sc.nextInt();
int[] pre = new int[n + 1];
for (int i = 1; i < n + 1; i++) {// 初始化
pre[i] = i;
}
for (int i = 0; i < m; i++) {
int x = sc.nextInt();
int y = sc.nextInt();
join(pre, x, y);
}
int count = 0;
for (int i = 1; i < n + 1; i++) {
if (pre[i] == i)
count++;
}
System.out.println(count - 1);
}
}
}