找亲戚——并查集
再次谈起什么是并查集?
在计算机科学中,并查集是一种树型的数据结构,用于处理一些不交集(Disjoint Sets)的合并及查询问题。有一个联合-查找算法(Union-find Algorithm)定义了两个用于此数据结构的操作:
Find:确定元素属于哪一个子集。它可以被用来确定两个元素是否属于同一子集。
Union:将两个子集合并成同一个集合。
由于支持这两种操作,一个不相交集也常被称为联合-查找数据结构(Union-find Data Structure)或合并-查找集合(Merge-find Set)。
为了更加精确的定义这些方法,需要定义如何表示集合。一种常用的策略是为每个集合选定一个固定的元素,称为代表,以表示整个集合。接着,Find(x)Find(x) 返回 xx 所属集合的代表,而 Union 使用两个集合的代表作为参数。
并查集概念
在一些应用问题中,需要将n个不同的元素划分成一些不相交的集合。开始时,每个元素自成一个单元素集合,然后按一定的规律将归于同一组元素的集合合并。在此过程中要反复用到查询某一个元素归属于那个集合的运算。适合于描述这类问题的抽象数据类型称为并查集(union-findset)。
并查集经典案例——找亲戚
问题描述:
给出总人数n和k对关系,然后给出p次关系询问
输入说明:
第一行输入两个正整数,分别代表总人数和关系数
下面k行代表k对关系
再下面一行输入一个正整数p,
下面p行代表p次关系询问
输出说明:
输出p行,每一行代表1次询问的回答,若有亲戚关系,则输出yes,反之输出no
输入示例1:
9 7
2 4
5 7
1 3
8 9
1 2
5 6
2 3
3
1 9
5 6
4 8
输出示例1:
no
yes
no
案例代码
1 public class Main { 2 3 /** 4 * 查询 5 */ 6 public static int find(int x, int[] parent) { 7 if (parent[x] == x) { 8 // 直接返回 9 return parent[x]; 10 } 11 // 递归找祖先 12 // 将当前节点的父亲设置为祖先,可以为之后的查询减少递归层数,提高算法的执行效率 13 // 关键代码 14 parent[x] = find(parent[x], parent); 15 return parent[x]; 16 } 17 18 /** 19 * 合并 20 */ 21 public static void union(int a, int b, int[] parent) { 22 // 各自找祖先 23 int parent_a = find(a, parent); 24 int parent_b = find(b, parent); 25 // 将a祖先的祖先设置为b的祖先 26 parent[parent_a] = parent_b; 27 } 28 29 /** 30 * 初始化 31 */ 32 public static void init(int[] parent) { 33 for (int i = 0; i < parent.length; i++) { 34 parent[i] = i; 35 } 36 } 37 38 public static void main(String[] args) { 39 // 设定人数,设定亲戚关系数 40 Scanner input = new Scanner(System.in); 41 int n = input.nextInt(); 42 // 一开始,初始化自己就为自己的祖先,因为这里我设置人的编号从1~n,所以数组长度要开n+1 43 int[] parent = new int[n + 1]; 44 init(parent); 45 int k = input.nextInt(); 46 for (int i = 0; i < k; i++) { 47 // 合并 48 int a = input.nextInt(); 49 int b = input.nextInt(); 50 union(a, b, parent); 51 } 52 53 // 接收询问次数 54 int p = input.nextInt(); 55 List<String> list = new ArrayList<>(); 56 for (int i = 0; i < p; i++) { 57 int a = input.nextInt(); 58 int b = input.nextInt(); 59 // 分别找各自祖先 60 int parent_a = find(a, parent); 61 int parent_b = find(b, parent); 62 if (parent_a == parent_b) { 63 list.add("yes"); 64 } else { 65 list.add("no"); 66 } 67 } 68 69 for (int i = 0; i < list.size(); i++) { 70 System.out.println(list.get(i)); 71 } 72 } 73 }