并查集--basic
public class UnionFind1 { private int[] parent; //数组,表示并查集所有元素的集合号 private int size; //表示并查集元素个数 public UnionFind1(int size) { //并查集初始化 this.size = size; parent = new int[size]; for (int i = 0; i < size; i++) { parent[i] = i; } } /** * 查看元素所属集合 * * @param element * @return */ private int find(int element) { return parent[element]; } /** * 判断两个集合是否在同一个集合 * * @param firstElement * @param secondElement * @return */ public boolean isConnected(int firstElement, int secondElement) { return find(firstElement) == find(secondElement); } /** * 合并firstElement,secondElement两个元素所在集合 * 将firstElement集合中所有元素的集合号都变为secondElement,就是认为是将两个集合合并 * * @param firstElement * @param secondElement */ public void unionElements(int firstElement, int secondElement) { int firstUnion = find(firstElement); int secondUnion = find(secondElement); if (firstUnion != secondUnion) { for (int i = 0; i < size; i++) { if (parent[i] == firstUnion) { parent[i] = secondUnion; } } } } private void printArray() { for (int id : this.parent) { System.out.print(id + "\t"); } System.out.println(); } public static void main(String[] args) { int n = 10; UnionFind1 union = new UnionFind1(n); System.out.println("初始:"); union.printArray(); System.out.println("连接了5 6"); union.unionElements(5, 6); union.printArray(); System.out.println("连接了1 2"); union.unionElements(1, 2); union.printArray(); System.out.println("连接了2 3"); union.unionElements(2, 3); union.printArray(); System.out.println("连接了1 4"); union.unionElements(1, 4); union.printArray(); System.out.println("连接了1 5"); union.unionElements(1, 5); union.printArray(); System.out.println("1 6 是否连接:" + union.isConnected(1, 6)); System.out.println("1 8 是否连接:" + union.isConnected(1, 8)); } }
快速合并
public class UnionFind2 { private int[] parent; private int size; public UnionFind2(int size) { //初始化并查集 this.size = size; parent = new int[size]; for (int i = 0; i < size; i++) { parent[i] = i; } } /** * 查找element集合的头结点 * element=parent[element]:说明element元素是一个集合的头结点或者是自己一个集合 * * @param element * @return */ public int find(int element) { while (element != parent[element]) {//此时说明element已不是自己一个结点了,所以通过循环找寻element所属集合的头结点 element = parent[element]; } return element; // } /** * 判断两个元素是否是一个集合:只需要判断两个元素所属集合的头结点是否相同即可 * * @param firstElement * @param secondElement * @return */ public boolean isConnected(int firstElement, int secondElement) { int firstUnion = find(firstElement); int secondUnion = find(secondElement); return firstUnion == secondUnion; } /** * 合并firstElement,secondElement所在的两个集合 * 将firstElement集合的头结点指向secondElement集合的头结点 * * @param firstElement * @param secondElement */ public void unionElements(int firstElement, int secondElement) { int firstUnion = find(firstElement); int secondUnion = find(secondElement); if (firstUnion != secondUnion) { parent[firstElement] = secondUnion; } } /** * 打印每个元素所属集合的小组号,即它的上一个结点号 */ private void printArray() { for (int parent : parent) { System.out.print(parent + " "); } System.out.println(); } public static void main(String[] args) { int n = 10; UnionFind2 union = new UnionFind2(n); System.out.println("初始:"); union.printArray(); System.out.println("连接了5 6"); union.unionElements(5, 6); union.printArray(); System.out.println("连接了1 2"); union.unionElements(1, 2); union.printArray(); System.out.println("连接了2 3"); union.unionElements(2, 3); union.printArray(); System.out.println("连接了1 4"); union.unionElements(1, 4); union.printArray(); System.out.println("连接了1 5"); union.unionElements(1, 5); union.printArray(); System.out.println("1 6 是否连接:" + union.isConnected(1, 6)); System.out.println("1 8 是否连接:" + union.isConnected(1, 8)); } }
快速合并--weight
public class UnionFind3 { private int[] parent; private int[] weight; private int size; public UnionFind3(int size) { this.parent = new int[size]; this.weight = new int[size]; this.size = size; for (int i = 0; i < size; i++) { this.parent[i] = i; this.weight[i] = 1; } } /** * 查找元素所属集合的头结点 * * @param element * @return */ public int find(int element) { while (element != parent[element]) { element = parent[element]; } return element; } /** * 判断两个元素是否是一个集合 * * @param firstElement * @param secondElement * @return */ public boolean isConnected(int firstElement, int secondElement) { return find(firstElement) == find(secondElement); } public void unionElements(int firstElement, int secondElement) { int firstRoot = find(firstElement); int secondRoot = find(secondElement); if (firstRoot == secondRoot) {//已经是同一个集合的元素就不用再合并了 return; } //集合的子元素多的头结点,合并之后仍然做头结点 if (weight[firstRoot] > weight[secondRoot]) { parent[secondRoot] = firstRoot; weight[firstRoot] += weight[secondRoot]; } else { parent[firstRoot] = secondRoot; weight[secondRoot] += weight[firstRoot]; } } /** * 打印parent数组 */ public void printArray(int[] arr) { for (int parent : arr) { System.out.print(parent + "\t"); } System.out.println(); } public static void main(String[] args) { int n = 10; UnionFind3 union = new UnionFind3(n); System.out.println("初始parent:"); union.printArray(union.parent); System.out.println("初始weight:"); union.printArray(union.weight); System.out.println("连接了5 6 之后的parent:"); union.unionElements(5, 6); union.printArray(union.parent); System.out.println("连接了5 6 之后的weight:"); union.printArray(union.weight); System.out.println("连接了1 2 之后的parent:"); union.unionElements(1, 2); union.printArray(union.parent); System.out.println("连接了1 2 之后的weight:"); union.printArray(union.weight); System.out.println("连接了2 3 之后的parent:"); union.unionElements(2, 3); union.printArray(union.parent); System.out.println("连接了2 3 之后的weight:"); union.printArray(union.weight); System.out.println("连接了1 4 之后的parent:"); union.unionElements(1, 4); union.printArray(union.parent); System.out.println("连接了1 4 之后的weight:"); union.printArray(union.weight); System.out.println("连接了1 5 之后的parent:"); union.unionElements(1, 5); union.printArray(union.parent); System.out.println("连接了1 5 之后的weight:"); union.printArray(union.weight); System.out.println("1 6 是否连接:" + union.isConnected(1, 6)); System.out.println("1 8 是否连接:" + union.isConnected(1, 8)); } }
快速合并--height
public class UnionFind4 { private int[] parent; private int[] height; int size; public UnionFind4(int size) { this.size = size; this.parent = new int[size]; this.height = new int[size]; for (int i = 0; i < size; i++) { parent[i] = i; height[i] = 1; } } public int find(int element) { while (element != parent[element]) { element = parent[element]; } return element; } public boolean isConnected(int firstElement, int secondElement) { return find(firstElement) == find(secondElement); } public void unionElements(int firstElement, int secondElement) { int firstRoot = find(firstElement); int secondRoot = find(secondElement); if (firstRoot == secondRoot) { return; } if (height[firstRoot] > height[secondRoot]) { parent[secondRoot] = firstRoot; } else if (height[firstRoot] < height[secondRoot]) { parent[firstRoot] = secondRoot; } else { parent[firstRoot] = secondRoot; height[secondRoot] += 1; } } private void printArray(int[] arr) { for (int parent : arr) { System.out.print(parent + " "); } System.out.println(); } public static void main(String[] args) { int n = 10; UnionFind4 union = new UnionFind4(n); System.out.println("初始parent:"); union.printArray(union.parent); System.out.println("初始height:"); union.printArray(union.height); System.out.println("连接了5 6 之后的parent:"); union.unionElements(5, 6); union.printArray(union.parent); System.out.println("连接了5 6 之后的height:"); union.printArray(union.height); System.out.println("连接了1 2 之后的parent:"); union.unionElements(1, 2); union.printArray(union.parent); System.out.println("连接了1 2 之后的height:"); union.printArray(union.height); System.out.println("连接了2 3 之后的parent:"); union.unionElements(2, 3); union.printArray(union.parent); System.out.println("连接了2 3 之后的height:"); union.printArray(union.height); System.out.println("连接了1 4 之后的parent:"); union.unionElements(1, 4); union.printArray(union.parent); System.out.println("连接了1 4 之后的height:"); union.printArray(union.height); System.out.println("连接了1 5 之后的parent:"); union.unionElements(1, 5); union.printArray(union.parent); System.out.println("连接了1 5 之后的height:"); union.printArray(union.height); System.out.println("1 6 是否连接:" + union.isConnected(1, 6)); System.out.println("1 8 是否连接:" + union.isConnected(1, 8)); } }
路径压缩
public class UnionFind5 { private int[] parent; private int[] height; int size; public UnionFind5(int size) { this.size = size; this.parent = new int[size]; this.height = new int[size]; for (int i = 0; i < size; i++) { parent[i] = i; height[i] = 1; } } public int find(int element) { while (element != parent[element]) { parent[element]=parent[parent[element]];//对于height比较大的,可以压缩路径 element = parent[element]; } return element; } public boolean isConnected(int firstElement, int secondElement) { return find(firstElement) == find(secondElement); } public void unionElements(int firstElement, int secondElement) { int firstRoot = find(firstElement); int secondRoot = find(secondElement); if (firstRoot == secondRoot) { return; } if (height[firstRoot] > height[secondRoot]) { parent[secondRoot] = firstRoot; } else if (height[firstRoot] < height[secondRoot]) { parent[firstRoot] = secondRoot; } else { parent[firstRoot] = secondRoot; height[secondRoot] += 1; } } private void printArray(int[] arr) { for (int parent : arr) { System.out.print(parent + " "); } System.out.println(); } public static void main(String[] args) { int n = 10; UnionFind5 union = new UnionFind5(n); System.out.println("初始parent:"); union.printArray(union.parent); System.out.println("初始height:"); union.printArray(union.height); System.out.println("连接了5 6 之后的parent:"); union.unionElements(5, 6); union.printArray(union.parent); System.out.println("连接了5 6 之后的height:"); union.printArray(union.height); System.out.println("连接了1 2 之后的parent:"); union.unionElements(1, 2); union.printArray(union.parent); System.out.println("连接了1 2 之后的height:"); union.printArray(union.height); System.out.println("连接了2 3 之后的parent:"); union.unionElements(2, 3); union.printArray(union.parent); System.out.println("连接了2 3 之后的height:"); union.printArray(union.height); System.out.println("连接了1 4 之后的parent:"); union.unionElements(1, 4); union.printArray(union.parent); System.out.println("连接了1 4 之后的height:"); union.printArray(union.height); System.out.println("连接了1 5 之后的parent:"); union.unionElements(1, 5); union.printArray(union.parent); System.out.println("连接了1 5 之后的height:"); union.printArray(union.height); System.out.println("1 6 是否连接:" + union.isConnected(1, 6)); System.out.println("1 8 是否连接:" + union.isConnected(1, 8)); } }
例题
public class Main { private int[] parent; private int[] weight; private int size; private int groups; public Main(int size) { this.size = size; this.groups = size; this.parent = new int[size]; this.weight = new int[size]; for (int i = 0; i < size; i++) { parent[i] = i; weight[i] = 1; } } public int find(int element) { while (element != parent[element]) { element = parent[element]; } return element; } public boolean isConnected(int firstElement, int secondElement) { return find(firstElement) == find(secondElement); } public void unionElement(int firstElement, int secondElement) { int firstRoot = find(firstElement); int secondRoot = find(secondElement); if (firstRoot == secondRoot) { return; } if (weight[firstRoot] < weight[secondRoot]) { parent[firstRoot] = secondRoot; weight[secondRoot] += weight[firstRoot]; } else { parent[secondRoot] = firstRoot; weight[firstRoot] += weight[secondRoot]; } this.groups--; } public int getGroups() { return this.groups; } public void printArray(int[] arr) { for (int parent : arr) { System.out.print(parent + " "); } System.out.println(); } public static void main(String[] args) { Scanner scan = new Scanner(System.in); int n = scan.nextInt(); for (int i = 0; i < n; i++) { int N = scan.nextInt(); Main m = new Main(N); int M = scan.nextInt(); for (int j = 0; j < M; j++) { int a = scan.nextInt()-1; int b = scan.nextInt()-1; m.unionElement(a, b); } System.out.println(m.getGroups()); } } }