代码随想录训练营 Day55打卡 图论part05 并查集理论基础 107. 寻找存在的路径

代码随想录训练营 Day55打卡 图论part05

一、并查集理论基础

并查集(Disjoint Set Union,简称 DSU 或 Union-Find)是一种用于处理动态连通性问题的数据结构,常用于解决图的连通性问题,如判断两个节点是否属于同一个连通分量,或者合并两个节点所属的集合。它可以在近乎常数时间内完成查询和合并操作,常用于图论算法中,如 Kruskal 算法求最小生成树。

并查集的核心操作:

  1. 查找(Find):查找元素所属的集合(找到该元素的代表节点)。
  2. 合并(Union):将两个元素所属的集合合并。

基础理论:

  • 每个元素最初在自己独立的集合中,视为一个单节点的树。
  • 当进行合并操作时,我们通过将一棵树的根节点指向另一棵树的根节点来合并集合。
  • 使用路径压缩(Path Compression)可以在查找过程中扁平化树结构,加快后续查找。

Python 实现并查集

下面是并查集的 Python 实现,包含路径压缩和按秩合并的优化:

python 复制代码
n = 1005  # n 根据题目中节点数量而定,可以根据实际情况调整
father = list(range(n))  # 初始化父节点数组,每个节点的父节点是自己

# 并查集初始化
def init():
    global father
    father = list(range(n))  # 重新初始化父节点数组

# 并查集里寻根的过程(路径压缩)
def find(u):
    if u == father[u]:
        return u
    father[u] = find(father[u])  # 路径压缩
    return father[u]

# 判断 u 和 v 是否属于同一个集合(是否连通)
def isSame(u, v):
    return find(u) == find(v)

# 将 v -> u 这条边加入并查集
def join(u, v):
    root_u = find(u)  # 寻找 u 的根
    root_v = find(v)  # 寻找 v 的根
    if root_u != root_v:  # 如果根不同,则合并
        father[root_v] = root_u

二、卡码107. 寻找存在的路径

题目描述

给定一个包含 n 个节点的无向图中,节点编号从 1 到 n (含 1 和 n )。

你的任务是判断是否有一条从节点 source 出发到节点 destination 的路径存在。
输入描述

第一行包含两个正整数 N 和 M,N 代表节点的个数,M 代表边的个数。

后续 M 行,每行两个正整数 s 和 t,代表从节点 s 与节点 t 之间有一条边。

最后一行包含两个正整数,代表起始节点 source 和目标节点 destination。
输出描述

输出一个整数,代表是否存在从节点 source 到节点 destination 的路径。如果存在,输出 1;否则,输出 0。
输入示例

5 4

1 2

1 3

2 4

3 4

1 4
输出示例

1
提示信息

本题是典型的 并查集(Union-Find) 问题,要求判断图中两个节点是否在同一个连通分量内,也就是从 source 节点是否能到达 destination 节点。

并查集解法思路

  1. 初始化并查集:每个节点都自成一个集合,初始时父节点为其自身。
  2. 合并集合:通过输入的边,将两个节点所在的集合进行合并(即将这两个节点连接起来)。
  3. 判断连通性:查询 source 和 destination 节点是否在同一个集合(即是否可以互相到达)。

代码实现

python 复制代码
class UnionFind:
    def __init__(self, n):
        # 初始化,每个节点的父节点指向自己
        self.father = list(range(n + 1))

    # 寻找节点的根,并进行路径压缩
    def find(self, u):
        if u == self.father[u]:
            return u
        else:
            # 路径压缩,直接将当前节点的父节点指向根
            self.father[u] = self.find(self.father[u])
            return self.father[u]

    # 合并两个节点所在的集合
    def union(self, u, v):
        root_u = self.find(u)
        root_v = self.find(v)
        if root_u != root_v:
            # 将v的根节点连接到u的根节点上
            self.father[root_v] = root_u

    # 判断两个节点是否在同一个集合
    def isConnected(self, u, v):
        return self.find(u) == self.find(v)

# 主函数,处理输入输出
def main():
    # 读取节点和边的数量
    n, m = map(int, input().split())

    # 初始化并查集
    uf = UnionFind(n)

    # 处理每条边
    for _ in range(m):
        s, t = map(int, input().split())
        uf.union(s, t)  # 合并节点s和t所在的集合

    # 读取起始节点source和目标节点destination
    source, destination = map(int, input().split())

    # 判断source和destination是否连通
    if uf.isConnected(source, destination):
        print(1)
    else:
        print(0)

# 调用主函数
if __name__ == "__main__":
    main()
  1. UnionFind 类:

init :初始化时,将每个节点的父节点设为自身,表示每个节点自成一个集合。
find :递归查找某个节点的根节点,并在递归返回时进行路径压缩,将节点直接指向根节点,从而加速后续的查找操作。
union :合并两个节点所在的集合。通过 find 方法找到它们的根节点,如果根节点不同,则将一个根节点连接到另一个根节点。
isConnected:判断两个节点是否属于同一个集合,即它们的根节点是否相同。

  1. main 函数:

读取输入的节点数 n 和边数 m,初始化并查集。

处理每条边,使用 union 方法将相连的节点合并。

最后,使用 isConnected 方法判断 source 和 destination 是否在同一个集合中,输出 1 表示连通,0 表示不连通。

卡码题目链接
题目文章讲解

相关推荐
凌肖战2 分钟前
力扣上刷题之C语言实现(数组)
c语言·算法·leetcode
秋夫人29 分钟前
B+树(B+TREE)索引
数据结构·算法
代码雕刻家1 小时前
数据结构-3.1.栈的基本概念
c语言·开发语言·数据结构
梦想科研社1 小时前
【无人机设计与控制】四旋翼无人机俯仰姿态保持模糊PID控制(带说明报告)
开发语言·算法·数学建模·matlab·无人机
Milo_K1 小时前
今日 leetCode 15.三数之和
算法·leetcode
Darling_001 小时前
LeetCode_sql_day28(1767.寻找没有被执行的任务对)
sql·算法·leetcode
AlexMercer10121 小时前
【C++】二、数据类型 (同C)
c语言·开发语言·数据结构·c++·笔记·算法
Greyplayground1 小时前
【算法基础实验】图论-BellmanFord最短路径
算法·图论·最短路径
蓑 羽1 小时前
力扣438 找到字符串中所有字母异位词 Java版本
java·算法·leetcode
源代码:趴菜1 小时前
LeetCode63:不同路径II
算法·leetcode·职场和发展