代码随想录训练营 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 表示不连通。

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

相关推荐
小刘|10 分钟前
《Java 实现希尔排序:原理剖析与代码详解》
java·算法·排序算法
jjyangyou15 分钟前
物联网核心安全系列——物联网安全需求
物联网·算法·安全·嵌入式·产品经理·硬件·产品设计
van叶~31 分钟前
算法妙妙屋-------1.递归的深邃回响:二叉树的奇妙剪枝
c++·算法
简简单单做算法32 分钟前
基于Retinex算法的图像去雾matlab仿真
算法·matlab·图像去雾·retinex
云卓SKYDROID1 小时前
除草机器人算法以及技术详解!
算法·机器人·科普·高科技·云卓科技·算法技术
半盏茶香1 小时前
【C语言】分支和循环详解(下)猜数字游戏
c语言·开发语言·c++·算法·游戏
徐子童1 小时前
双指针算法习题解答
算法
想要打 Acm 的小周同学呀1 小时前
LRU缓存算法
java·算法·缓存
劲夫学编程2 小时前
leetcode:杨辉三角
算法·leetcode·职场和发展
毕竟秋山澪2 小时前
孤岛的总面积(Dfs C#
算法·深度优先