1 今日打卡
并查集基础理论 并查集理论基础 | 代码随想录
寻找存在的路线 107. 寻找存在的路线
2 并查集基础理论
当我们需要判断两个元素是否在同一个集合里的时候,我们就要想到用并查集。
模板:




3 寻找存在的路径
3.1 思路
初始化并查集:为每个节点建立独立的集合(父节点指向自己);
合并连通节点:遍历所有边,将每条边的两个节点合并到同一个集合中;
判断连通性:检查目标两个节点是否属于同一个集合(根节点相同),输出结果。
3.2 实现代码
java
import java.util.*;
public class Main {
// 定义并查集内部类,用于管理节点的连通关系
static class disJoint {
// 父节点数组:father[i]表示节点i的父节点(静态仅因本题单实例,实际建议去掉static)
public static int[] father;
// 并查集构造方法:初始化n个节点的父节点
public disJoint(int n) {
// 节点编号从1开始(题目常见输入习惯),数组长度设为n+1
father = new int[n + 1];
// 初始化:每个节点的父节点是自己(独立集合)
for (int i = 0; i <= n; i++) {
father[i] = i;
}
}
// 查找节点u的根节点(带路径压缩,优化查找效率)
public int find(int u) {
// 递归终止条件:u是自己的父节点(u是根节点)
if (u == father[u]) {
return u;
}
// 路径压缩:将u的父节点直接指向根节点(扁平化树结构)
father[u] = find(father[u]);
// 返回压缩后的根节点
return father[u];
}
// 合并两个节点u和v所在的集合
public void join(int u, int v) {
// 先找到u的根节点
u = find(u);
// 先找到v的根节点
v = find(v);
// 如果根节点相同,说明已在同一集合,无需合并
if (u == v) {
return;
}
// 合并:将v的根节点指向u的根节点(统一集合)
father[v] = u;
}
// 判断两个节点是否在同一个集合(是否连通)
public boolean isSame(int u, int v) {
// 找到u的根节点
u = find(u);
// 找到v的根节点
v = find(v);
// 根节点相同则连通,否则不连通
return u == v;
}
}
// 主方法:程序入口,处理输入、调用并查集、输出结果
public static void main(String[] args) {
// 创建Scanner对象,读取控制台输入
Scanner sc = new Scanner(System.in);
// 读取第一个整数n(节点总数),第二个整数m(边的总数)
int n = sc.nextInt(), m = sc.nextInt();
// 初始化并查集,容量为n
disJoint dj = new disJoint(n);
// 遍历m条边,合并每条边的两个节点
for (int i = 0; i < m; i++) {
// 读取当前边的两个节点a和b
int a = sc.nextInt(), b = sc.nextInt();
// 合并节点a和b到同一集合
dj.join(a, b);
}
// 读取需要判断连通性的两个节点from和to
int from = sc.nextInt(), to = sc.nextInt();
// 判断两个节点是否连通
if (dj.isSame(from, to)) {
// 连通则输出1
System.out.println(1);
} else {
// 不连通则输出0
System.out.println(0);
}
// 关闭Scanner,释放资源
sc.close();
}
}