代码随想录算法训练营第五十天 | 图论理论基础、深搜理论基础、98. 所有可达路径、广搜理论基础

一、图论理论基础

文章链接:图论理论基础 | 代码随想录 (programmercarl.com)

图的种类:有向图 和 无向图。

度:无向图中有几条边连接该节点,该节点就有几度。

连通性
连通图:无向图 中,任何两个节点可以相互到达。
强连通图:有向图 中,任何两个节点可以相互到达。
连通分量:无向图 中的 极大 连通子图称之为该图的一个连通分量。
强连通分量:有向图  极大 强连通子图称之为该图的强连通分量。

二、深搜理论基础(DFS)

文章链接:深度优先搜索理论基础 | 代码随想录 (programmercarl.com)

深搜(dfs)和广搜(bfs)区别

dfs是可一个方向一直搜索下去;
bfs是先把本节点连接的所有节点遍历一遍,然后走到下一个节点时,再遍历一遍。

深搜三部曲

1. 确定递归函数 和 参数;
2. 确定终止条件;
3. 处理目前搜索节点出发的路径。(for 循环遍历 目前搜索节点 所能到的所有节点)

Note:dfs 遇到黄河回头的过程就是回溯算法。

"""
DFS模板
"""
def DFS(graph, s):
    stack = []
    stack.append(s)
    # 创建一个哈希表存储遍历过的节点
    seen = {}
    seen.add(s)
    # 当栈不为空时
    while (len(stack) > 0):
        # 从栈中弹出最后一个元素
        vertex = queue.pop()
        # 找到vertex的邻接节点
        nodes = graph[vertex]
        # 遍历节点
        for w in nodes:
            # 如果这些邻接节点没有走过,将其添加到队列中
            if w not in seen:
                stack.append(w)
                seen.add(w)
        print(vertex)

三、98. 所有可达路径

题目链接:98. 所有可达路径 (kamacoder.com)
文章讲解:代码随想录 (programmercarl.com)——98. 所有可达路径

"""
邻接矩阵写法
"""
# 1. 确定递归函数和参数
# graph: 存当前的图
# x: 遍历节点
# n: 终点
# path: 1节点到终点的路径
# result: 收集符合条件的路径
def dfs(graph, x, n, path, result):
    # 2. 确定终止条件,当前遍历节点 x 为终点 n
    if x == n:
        result.append(path.copy())
        return
    
    # 3. 处理目前搜索节点出发的路径
    # 遍历 x 连接的所有节点
    for i in range(1, n + 1):
        # 找到 x 指向的节点
        if graph[x][i] == 1:       
            # 将选中的 x 所指向的节点加入到单一路径中
            path.append(i)
            # 进入下一层递归
            dfs(graph, i, n, path, result)
            # 回溯,撤销本节点
            path.pop()                      
            
def main():
    # 读取节点数和边数
    n, m = map(int, input().split())
    # 创建一个全0,大小为 n+1 行,n+1 列的邻接矩阵 graph
    graph = [[0]*(n + 1) for _ in range(n + 1)]     
    
    # 循环 m 次,读取每条边的信息
    for _ in range(m):
        # 每次循环中读取起点和终点
        s, t = map(int, input().split())
        # 将邻接矩阵中对应起点和终点的元素设置为1
        graph[s][t] = 1
    
    # 创建一个列表存储结果
    result = []
    dfs(graph, 1, n, [1], result)
    
    # 如果没有找到路径,返回-1
    if not result:
        print(-1)
    else:
        # 遍历 result 中每一个路径 
        for path in result:
            # 将路径每个节点转换为字符串,并用空格连接
            print(' '.join(map(str, path)))
            

if __name__ == "__main__":
    main()
"""
邻接表写法
"""
from collections import defaultdict

# 收集符合条件的路径
result = []  
# 1节点到终点的路径
path = []  

# 1. 确定递归函数和参数
def dfs(graph, x, n):
    # 2. 确定终止条件,当前遍历节点 x 为终点 n
    if x == n:
        result.append(path.copy())
        return
    
    # 3. 处理目前搜索节点出发的路径
    # 找到 x指向的节点
    for i in graph[x]: 
        # 遍历到的节点加入到路径中来
        path.append(i)  
        # 进入下一层递归
        dfs(graph, i, n)  
        # 回溯,撤销本节点
        path.pop() 

def main():
    n, m = map(int, input().split())

    # 邻接表
    graph = defaultdict(list)  
    
    for _ in range(m):
        s, t = map(int, input().split())
        graph[s].append(t)

    # 无论什么路径已经是从1节点出发
    path.append(1)  
    # 开始遍历
    dfs(graph, 1, n) 

    # 输出结果
    if not result:
        print(-1)
    for pa in result:
        print(' '.join(map(str, pa)))

if __name__ == "__main__":
    main()

四、广搜理论基础(BFS)

文章链接:广度优先搜索理论基础 | 代码随想录 (programmercarl.com)

使用场景:适合解决两点之间最短路径问题。

特点:源点开始,一圈一圈向外遍历,由近到远,由内而外。

队列实现广搜三部曲

1. 源点进队;
2. 队列不为空时,拿出队首元素;
3. 对队首元素进行扩展(遍历cur的邻接表),未被访问过的节点进队。
Note:保证队列中,距离单调递增。

"""
BFS模板
"""
# s表示第一个开始的节点
def BFS(graph, s):
    queue = []
    queue.append(s)
    # 创建一个哈希表存储遍历过的节点
    seen = set()
    seen.add(s)
    # 当队列不为空时
    while (len(queue) > 0):
        # 从队列中取出第一个节点
        vertex = queue.pop(0)
        # 找到vertex的邻接节点
        nodes = graph[vertex]
        # 遍历节点
        for w in nodes:
            # 如果这些邻接节点没有走过,将其添加到队列中
            if w not in seen:
                queue.append(w)
                seen.add(w)
        print(vertex)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值