并查集
并查集是一种非常精致而且实用的数据结构;它主要用于处理一些不相交集合的合并问题.一些常见的用途有求连通子树,求最小生成数和求最近公共祖先等.
并查集的主要操作有:
1.初始化(init)
2.查询(find)
3.合并(union)
假设有编号为1,2,3,4…,n的n个元素,我们用一个数组 fa[ ] 来存储每个元素的父节点,我们先将它们的父节点设为自己.
// 并查集
public class UnionFindSets {
int[] fa;
//1.初始化
public void init(int n) {
for (int i = 1; i <= n; i++) {
this.fa[i] = i;
}
}
//2.查询
//找到i的祖先直接返回,未进行路径压缩
public int find(int i) {
if (fa[i] == i) { //递归出口,当到达了祖先位置,就返回祖先;
return i;
} else {
return find(fa[i]); //不断往上查找祖先;
}
}
//3.合并
public void unionn(int i, int j) {
int i_fa = find(i);
int j_fa = find(j);
fa[i_fa] = j_fa;
}
}
路径压缩
//查询
//路径压缩
public int find(int i) {
if (fa[i] == i) {
return i;
} else {
fa[i] = find(fa[i]); //该步进行了路径压缩
return fa[i]; //这次不返回它的祖先,直接返回它的父节点
}
}
典例实践
例子: 现在有若干家族图谱关系,给出了一些亲戚关系,如Marry和Tom是亲戚,Tom和Ben是亲戚等等,从这些信息中,你可以推出Marry和Ben是亲戚,请写一个程序,对于我们的关于亲戚关系的提问,以最快的速度给出答案.
[输入格式]
第一部分是以N,M开始,N为人数(1<=N<=20000),这些人的编号为1,2,3,...,N;下面有M行(1<=M<=1000000)
每行有两个数a,b 表示a和b是亲戚.
第二部分是以Q开始,以下Q行有Q个询问(1<=Q<=1000000),每行为c,d;表示询问c和d是否为亲戚关系.
[输出格式]
对于询问c,d,输出一行,若c,d为亲戚,则输出"YES",否则输出"NO";
[输入样例] [输出样例]
10 7
2 4
5 7
1 3
8 9
1 2
5 6
2 3
3
3 4 YES
7 10 NO
8 9 YES
代码如下:
import java.util.Scanner;
// 并查集
public class UnionFindSets {
static int[] fa;
//1.初始化
public static void init(int n) {
fa = new int[n + 1];
for (int i = 1; i <= n; i++) {
fa[i] = i;
}
}
//2.查询
//路径压缩
public static int find(int i) {
if (fa[i] == i) {
return i;
} else {
fa[i] = find(fa[i]); //该步进行了路径压缩
return fa[i]; //父节点作为根节点,直接返回它的父节点
}
}
//3.合并
public static void unionn(int i, int j) {
int i_fa = find(i); //找到i的祖先
int j_fa = find(j); //找到j的祖先
fa[i_fa] = j_fa; //让i的祖先指向j的祖先,其实j的祖先指向i的祖先也是可以的
}
//并查集典例实践
/*
例子: 现在有若干家族图谱关系,给出了一些亲戚关系,如Marry和Tom是亲戚,Tom和Ben是亲戚等等,
从这些信息中,你可以推出Marry和Ben是亲戚,请写一个程序,对于我们的关于亲戚关系的提问,以最快的
速度给出答案.
[输入格式]
第一部分是以N,M开始,N为人数(1<=N<=20000),这些人的编号为1,2,3,...,N;下面有M行(1<=M<=1000000)
每行有两个数a,b 表示a和b是亲戚.
第二部分是以Q开始,以下Q行有Q个询问(1<=Q<=1000000),每行为c,d;表示询问c和d是否为亲戚关系.
[输出格式]
对于询问c,d,输出一行,若c,d为亲戚,则输出"YES",否则输出"NO";
[输入样例] [输出样例]
10 7
2 4
5 7
1 3
8 9
1 2
5 6
2 3
3
3 4 YES
7 10 NO
8 9 YES
*/
public static void main(String[] args) {
int n, m, x, y, q;
Scanner sc = new Scanner(System.in);
n = sc.nextInt();
init(n);
m = sc.nextInt();
for (int i = 1; i <= m; i++) {
x = sc.nextInt();
y = sc.nextInt();
unionn(x, y);
}
q = sc.nextInt();
System.out.println();
for (int i = 1; i <= q; i++) {
x = sc.nextInt();
y = sc.nextInt();
if (find(x) == find(y)) {
System.out.println("YES");
} else {
System.out.println("NO");
}
}
}
}