代码随想录算法训练营第五十五天 | 寻找存在的路径

目录

寻找存在的路径

思路

方法一: 并查集-卡哥

方法二:并查集


寻找存在的路径

给定一个包含 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

提示信息

数据范围:

1 <= M, N <= 100。

思路

本题是并查集基础题目。 如果还不了解并查集,可以看这里:并查集理论基础(opens new window)

并查集可以解决什么问题呢?

主要就是集合问题,两个节点在不在一个集合,也可以将两个节点添加到一个集合中

这里整理出我的并查集模板如下:

n = 1005 # n根据题目中节点数量而定,一般比节点数量大一点就好


# 并查集初始化
father = list(range(n + 1))
# 并查集里寻根的过程
def find(u) :
    if father[u] != u:
            father[u] = find(father[u])  # 路径压缩
        return father[u]

# 判断 u 和 v是否找到同一个根
def isSame(u, v) :
    u = find(u)
    v = find(v)
    return u == v


# 将v->u 这条边加入并查集
def join(u, v) :
    u = find(u) # 寻找u的根
    v = find(v) # 寻找v的根
    if (u == v) : return # 如果发现根相同,则说明在一个集合,不用两个节点相连直接返回
    father[v] = u

以上模板中,只要修改 n 大小就可以。

并查集主要有三个功能:

  1. 寻找根节点,函数:find(int u),也就是判断这个节点的祖先节点是哪个
  2. 将两个节点接入到同一个集合,函数:join(int u, int v),将两个节点连在同一个根节点上
  3. 判断两个节点是否在同一个集合,函数:isSame(int u, int v),就是判断两个节点是不是同一个根节点

简单介绍并查集之后,我们再来看一下这道题目。

为什么说这道题目是并查集基础题目,题目中各个点是双向图链接,那么判断 一个顶点到另一个顶点有没有有效路径其实就是看这两个顶点是否在同一个集合里。

如何算是同一个集合呢,有边连在一起,就算是一个集合。

此时我们就可以直接套用并查集模板。

使用 join(int u, int v)将每条边加入到并查集。

最后 isSame(int u, int v) 判断是否是同一个根 就可以了。

方法一: 并查集-卡哥

class UnionFind:
    def __init__(self, size):
        self.parent = list(range(size + 1))  # 初始化并查集

    def find(self, u):
        if self.parent[u] != u:
            self.parent[u] = self.find(self.parent[u])  # 路径压缩
        return self.parent[u]

    def union(self, u, v):
        root_u = self.find(u)
        root_v = self.find(v)
        if root_u != root_v:
            self.parent[root_v] = root_u

    def is_same(self, u, v):
        return self.find(u) == self.find(v)


def main():
    import sys
    input = sys.stdin.read
    data = input().split()
    
    index = 0
    n = int(data[index])
    index += 1
    m = int(data[index])
    index += 1
    
    uf = UnionFind(n)
    
    for _ in range(m):
        s = int(data[index])
        index += 1
        t = int(data[index])
        index += 1
        uf.union(s, t)
    
    source = int(data[index])
    index += 1
    destination = int(data[index])
    
    if uf.is_same(source, destination):
        print(1)
    else:
        print(0)

if __name__ == "__main__":
    main()

方法二:并查集

class Solution:
    def __init__(self) -> None:
        self.father = []

    def graph(self,n):
        for i in range(n):
            self.father.append(i)

    def is_Same(self,source,destination):
        source = self.find(source)
        destination = self.find(destination)
        return source == destination
    
    def find(self,ele):
        # # 写法一
        # if ele == self.father[ele]:
        #     return ele
        # else:
        #     self.father[ele] = self.find(self.father[ele])
        #     return self.father[ele]

        # 写法二

        if ele != self.father[ele]:
            self.father[ele] = self.find(self.father[ele])

        return self.father[ele]
    
    def join(self,u,v):
        u = self.find(u)
        v = self.find(v)

        if u != v:
            self.father[v] = u

def main():
    n,m = map(int,input().split())
    g = Solution()
    g.graph(n+1)

    for i in range(m):
        u,v = map(int,input().split())
        g.join(u,v)

    source,destination = map(int,input().split())

    print(1) if g.is_Same(source,destination) else print(0)

if __name__=="__main__":
    main()

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值