并查集
并查集解决的问题
- 将两个集合合并
- 询问两个元素是否在一个集合中
基本原理
用树的形式来维护每个集合,树根的编号就是整个集合的编号,每个节点存储他的父节点,p[x]表示x的父节点
问题1,如何判断树根:if(p[x] == x);
问题2,如何求x集合的编号: while(p[x] != x) x = p[x];
问题3,如何合并两个集合,px是x集合的编号,py是y的集合编号,令p[x]=y。
问题2优化:某个节点找到根节点之后,把整个路径上的点直接指向根节点。
例题
AcWing 836 合并集合
一共有n个数,编号是1~n,最开始每个数各自在一个集合中。
现在要进行m个操作,操作共有两种:
- “M a b”,将编号为a和b的两个数所在的集合合并,如果两个数已经在同一个集合中,则忽略这个操作;
- “Q a b”,询问编号为a和b的两个数是否在同一个集合中;
import java.util.*;
class UnionSet{
private final int N = 100010;
private int[] p = new int[N];
public UnionSet(){
for(int i = 0; i < N; i++){
p[i] = i;
}
}
// 找到该节点的root节点
public int find(int val){
int temp = val;
while(p[temp] != temp){
temp = p[temp];
}
p[val] = temp;
return temp;
}
public void union(int a,int b){
int pa = find(a);
int pb = find(b);
if(pa != pb) p[pa] = pb;
}
public boolean isunion(int a,int b){
int pa = find(a);
int pb = find(b);
if(pa != pb) return false;
else return true;
}
}
public class Main{
public static void main(String[] args){
Scanner Reader = new Scanner(System.in);
int n = Reader.nextInt();
int m = Reader.nextInt();
UnionSet us = new UnionSet();
while(m-- != 0){
String temp = Reader.next();
if(temp.equals("M")){
int v1 = Reader.nextInt(),v2 = Reader.nextInt();
us.union(v1,v2);
}
if(temp.equals("Q")){
if(us.isunion(Reader.nextInt(),Reader.nextInt()))
System.out.println("Yes");
else
System.out.println("No");
}
}
}
}
AcWing 837 连通块中点的数量
给定一个包含n个点(编号为1~n)的无向图,初始时图中没有边。
现在要进行m个操作,操作共有三种:
- “C a b”,在点a和点b之间连一条边,a和b可能相等;
- “Q1 a b”,询问点a和点b是否在同一个连通块中,a和b可能相等;
- “Q2 a”,询问点a所在连通块中点的数量;
import java.util.*;
class UnionSet{
private final int N = 100010;
private int[] p = new int[N];
private int[] size = new int[N];
public UnionSet(){
for(int i = 0; i < N; i++){
p[i] = i;
size[i] = 1;
}
}
// 找到该节点的root节点
public int find(int val){
int temp = val;
while(p[temp] != temp){
temp = p[temp];
}
p[val] = temp;
return temp;
}
public void union(int a,int b){
int pa = find(a);
int pb = find(b);
if(pa != pb) {
p[pa] = pb;
size[pb] += size[pa];
}
}
public boolean isunion(int a,int b){
int pa = find(a);
int pb = find(b);
if(pa != pb) return false;
else return true;
}
public int size(int a){
return size[find(a)];
}
}
public class Main{
public static void main(String[] args){
Scanner Reader = new Scanner(System.in);
int n = Reader.nextInt();
int m = Reader.nextInt();
UnionSet us = new UnionSet();
while(m-- != 0){
String temp = Reader.next();
if(temp.equals("C")){
int v1 = Reader.nextInt(),v2 = Reader.nextInt();
us.union(v1,v2);
}
if(temp.equals("Q1")){
if(us.isunion(Reader.nextInt(),Reader.nextInt()))
System.out.println("Yes");
else
System.out.println("No");
}
if(temp.equals("Q2")){
System.out.println(us.size(Reader.nextInt()));
}
}
}
}
来源:CSDN
作者:muzi刘
链接:https://blog.csdn.net/anying5823/article/details/104793753