代码随想录训练营 Day50打卡 图论part01 理论基础 98. 所有可达路径

news2024/9/23 11:15:45

代码随想录训练营 Day50打卡 图论part01

一、理论基础

DFS(深度优先搜索)和 BFS(广度优先搜索)在图搜索中的核心区别主要体现在搜索策略上:
1、搜索方向:

  • DFS:深度优先,一条路走到黑。DFS
    从起点开始,选择一个方向深入到底,遇到死胡同再回溯,换一个方向继续探索。这种方式适合解决路径和组合问题,常与递归和回溯算法结合使用。
  • BFS:广度优先,层层推进。BFS 以起点为中心,一层层扩展,首先访问所有与起点相邻的节点,然后再访问这些节点的下一层。BFS通常用于找到最短路径或解决需要按层次遍历的问题。

2、使用的数据结构:

  • DFS:采用 结构实现(递归隐式使用栈,或者显式使用栈数据结构)。
  • BFS:使用 队列 实现,遵循先入先出的原则,逐层访问节点。

3、空间和时间复杂度:

  • DFS:占用的内存相对较少,因其只需要记录当前路径和回溯过程中的节点。时间复杂度是 O(V + E),其中 V 是节点数,E 是边的数量。空间复杂度与递归深度有关,最坏情况下可能达到 O(V)。
  • BFS:需要存储每一层的节点,因此占用的内存较多。时间复杂度同样是 O(V + E),但空间复杂度通常是 O(V),因为要存储所有节点的状态和层次信息。

4、适用场景:

  • DFS:适合解决需要遍历到图的某个具体位置、回溯路径、组合搜索等问题,例如解决迷宫问题、找路径的所有可能解。
  • BFS:适合寻找最短路径或需要按层次访问图的场景,例如无权图中的最短路径问题。

DFS 框架简介

DFS 的基本框架依赖递归和回溯机制,关键在于路径处理和终止条件的设置:

void dfs(参数) {
    if (终止条件) {
        存放结果;
        return;
    }

    for (选择:本节点所连接的其他节点) {
        处理节点;
        dfs(图,选择的节点); // 递归
        回溯,撤销处理结果
    }
}

DFS 通过递归深入到图的尽头,然后再逐步回溯,处理可能的路径和解。

BFS 框架简介

BFS 以层次展开,可以用队列实现,框架如下:

void bfs(参数) {
    queue<Node> q;
    q.push(起点);

    while (!q.empty()) {
        Node current = q.front();
        q.pop();

        for (每一个与 current 相邻的节点) {
            处理节点;
            q.push(相邻节点);
        }
    }
}

BFS 的每层处理完当前层所有节点后,再进入下一层,保证了广度搜索的特点。

总结:DFS 和 BFS 是两种经典的搜索策略,DFS 更侧重于深度探索和回溯,而 BFS 则侧重于广度的逐层推进。理解它们的区别和适用场景有助于在不同问题中灵活选择合适的算法。

二、卡码98. 所有可达路径

题目描述
给定一个有 n 个节点的有向无环图,节点编号从 1 到 n。请编写一个函数,找出并返回所有从节点 1 到节点 n 的路径。每条路径应以节点编号的列表形式表示。
输入描述
第一行包含两个整数 N,M,表示图中拥有 N 个节点,M 条边
后续 M 行,每行包含两个整数 s 和 t,表示图中的 s 节点与 t 节点中有一条路径
输出描述
输出所有的可达路径,路径中所有节点之间空格隔开,每条路径独占一行,存在多条路径,路径输出的顺序可任意。如果不存在任何一条路径,则输出 -1。
注意输出的序列中,最后一个节点后面没有空格! 例如正确的答案是 1 3 5,而不是 1 3 5 , 5后面没有空格!
输入示例
5 5
1 3
3 5
1 2
2 4
4 5
输出示例
1 3 5
1 2 4 5
提示信息

用例解释:
有五个节点,其中的从 1 到达 5 的路径有两个,分别是 1 -> 3 -> 5 和 1 -> 2 -> 4 -> 5。
因为拥有多条路径,所以输出结果为:
1 3 5
1 2 4 5

1 2 4 5
1 3 5
都算正确。

邻接矩阵写法

代码实现思路:

  1. 图的表示:使用二维数组(邻接矩阵)来存储图,graph[x][y] 表示从节点 x 到节点 y 是否有边,如果有边则值为 1,否则为
    0。
  2. DFS 搜索:从节点 1 开始,使用深度优先搜索遍历图。如果到达终点(节点 n),将路径存储在 result
    中。每次递归调用前将当前节点加入路径,递归结束时通过回溯移除该节点。
  3. 递归终止条件:当到达终点节点 n 时,将当前路径存储在结果中,递归停止。
  4. 结果处理:如果没有找到从节点 1 到终点的路径,输出 -1,否则输出所有路径。
def dfs(graph, x, n, path, result):
    # 如果到达了终点(节点 n),将当前路径加入到结果中
    if x == n:
        result.append(path.copy())  # 复制当前路径,防止回溯时影响
        return
    # 遍历所有节点,看是否可以从当前节点 x 移动到节点 i
    for i in range(1, n + 1):
        if graph[x][i] == 1:  # 如果 x 可以到达 i
            path.append(i)  # 将 i 节点加入路径
            dfs(graph, i, n, path, result)  # 继续深度优先搜索
            path.pop()  # 回溯,将最后加入的节点从路径中移除

def main():
    # 输入节点数 n 和边数 m
    n, m = map(int, input().split())
    
    # 初始化邻接矩阵,大小为 (n+1) x (n+1),因为节点从 1 开始
    graph = [[0] * (n + 1) for _ in range(n + 1)]

    # 构建图,读入 m 条边
    for _ in range(m):
        s, t = map(int, input().split())  # 从 s 到 t 有一条边
        graph[s][t] = 1  # 在邻接矩阵中记录这条边

    result = []  # 存放所有从 1 到 n 的路径
    dfs(graph, 1, n, [1], result)  # 从节点 1 开始搜索,路径初始为 [1]

    # 如果没有找到任何路径,输出 -1,否则输出所有路径
    if not result:
        print(-1)
    else:
        for path in result:
            print(' '.join(map(str, path)))  # 将路径输出为空格分隔的字符串

if __name__ == "__main__":
    main()

邻接表写法

代码实现思路:

  1. 图的表示:使用 defaultdict(list)
    存储图的邻接表,每个节点存储与之相邻的节点列表。与邻接矩阵不同,邻接表节省了空间,只存储实际存在的边。
  2. DFS 搜索:同样从节点 1 开始,使用深度优先搜索。当到达终点节点 n 时,将当前路径存储在 result
    中。每次递归前将当前节点加入路径,递归结束时回溯。
  3. 结果处理:与邻接矩阵版本一样,输出结果或返回 -1。
from collections import defaultdict

result = []  # 收集所有从节点1到节点n的路径
path = []  # 当前路径

def dfs(graph, x, n):
    # 如果当前节点是终点(节点 n),将路径存储到结果中
    if x == n:
        result.append(path.copy())  # 复制路径,防止回溯影响
        return
    # 遍历当前节点 x 的所有相邻节点
    for i in graph[x]:
        path.append(i)  # 将当前节点加入路径
        dfs(graph, i, n)  # 递归搜索相邻节点
        path.pop()  # 回溯,撤销本节点

def main():
    # 输入节点数 n 和边数 m
    n, m = map(int, input().split())
    
    # 初始化邻接表,使用 defaultdict 使得添加边更方便
    graph = defaultdict(list)

    # 构建图,输入 m 条边
    for _ in range(m):
        s, t = map(int, input().split())  # 从 s 到 t 有一条边
        graph[s].append(t)  # 在邻接表中添加这条边

    path.append(1)  # 从节点 1 开始,初始路径为 [1]
    dfs(graph, 1, n)  # 开始搜索

    # 输出结果,如果没有路径输出 -1,否则输出路径
    if not result:
        print(-1)
    else:
        for pa in result:
            print(' '.join(map(str, pa)))  # 输出路径

if __name__ == "__main__":
    main()

题目链接
题目文章讲解

总结:

  1. 邻接矩阵适合处理稠密图,表示简单但占用空间较大,尤其当图的节点较多但边较少时会浪费空间。
  2. 邻接表适合处理稀疏图,能够节省空间,适合处理边较少的场景。
  3. DFS在这两种表示方式中的思路是一致的,只是访问方式不同:邻接矩阵中遍历二维数组,邻接表中遍历相邻节点的列表。
  4. 两种方法都使用了 回溯 的思想,每次递归进入一个新的节点,遍历完后需要撤销操作,即 回溯到上一层,确保路径恢复到原始状态。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2105607.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

突破教材,简单聊聊《文件系统》

文章目录 前言&#xff1a;文件系统的引入&#xff1a;认识物理磁盘&#xff1a; 对磁盘的存储进行逻辑抽象&#xff1a;LBA逻辑区块地址&#xff1a; &#x1f680;文件系统的理解&#xff1a;理解各个区段&#xff1a;&#x1f6f9;深入理解 inode&#xff1a;inode和文件名&…

9.4日常记录

一、索英笔试 1.实现strcpy 1.char src[] "Hello, World!";&#xff1a; 这里定义了一个字符数组。这个字符串 "Hello, World!" 的内容被直接存储在这个数组中&#xff0c;数组的大小由字符串的长度加上一个额外的位置用于存储字符串结束符\0自动确定。 …

CSS英文换行

在CSS中&#xff0c;如果你想让英文单词换行&#xff0c;可以使用word-break: break-all;属性。这个属性会强制浏览器在任何字符之间进行换行&#xff0c;即使没有空格或其他分隔符。 没有加样式前的运行结果 CSS样式 p {word-break: break-all; } 运行结果 这将确保段落内的…

【弱监督时间动作定位】Probabilistic Vision-Language Representation for WSTAL 论文阅读

Probabilistic Vision-Language Representation for Weakly Supervised Temporal Action Localization 论文阅读 Abstract1 Introduction2 RELATEDWORK2.1 Weakly Supervised Temporal Action Localization2.2 Vision Language Pre-training2.3 Probabilistic Representation 3…

VS2022卸载记录

Releases microsoft/VisualStudioUninstaller (github.com) 在上面的网址中下载压缩包 下载之后解压&#xff0c;之后选择红框文件&#xff0c;右键选择以管理员身份运行 输入Y&#xff0c;回车 &#xff0c;之后等待程序执行结束 该操作之后&#xff0c;我发现我的安装目录中…

CentOS7 MySQL 数据库基本使用

3.查看当前库中存在哪些表 mysql> show tables 4.查看表的结构 mysql> describe user mysql> describe mysql.user 5.查询数据库服务的基本信息 mysql> status 二、创建及删除库和表 1.创建新的库 CREATE DATABASE 语句&#xff1a;用于创建一个新的库&…

【音视频】播放音视频时发生了什么? 视频的编解码 H264是什么? MP4是什么?

目录 ✨播放一个视频的流程✨为什么要编码&#xff08;压缩&#xff09;视频数据&#xff1f;✨如何编码&#xff08;压缩&#xff09;数据&#x1f384;简单的例子&#x1f384;音视频编码方式&#x1f384;视频编码格式H264编码是什么&#xff1f;发展历程&#xff1f;H.264基…

使用python+opencv解析图像和文本数据

1. 创建虚拟环境 新建文件夹, 并在文件夹中创建虚拟环境,可以使用Vscode打开文件夹, 然后在终端中输入以下命令: python -m venv venv2. 激活虚拟环境 在终端中输入以下命令: venv\Scripts\activate3. 安装依赖 在终端中输入以下命令: pip install opencv-pythonpip inst…

docker pull命令拉取镜像失败的解决方案

docker pull命令拉取镜像失败的解决方案 一、执行docker pull命令&#xff0c;拉取镜像失败 报错信息&#xff1a;error pulling image configuration: Get https://production.cloudflare.docker.com/registry-v2/docker/registry/v2/blobs/sha256/51/5107333e08a87b836d48f…

第86集《大佛顶首楞严经》

《大佛顶如来密因修正了义诸菩萨万行首楞严经》。监院法师慈悲&#xff0c;诸位法师&#xff0c;诸位同学&#xff0c;阿弥陀佛&#xff01; 请大家打开讲义188面 我们这一科讲到&#xff0c;辛三、盗戒。透过大乘的理观跟事修&#xff0c;所谓大乘的戒法来对治偷盗的行为跟偷…

EasyExcel单行或多行表头的简单Excel导出

一般Excel不需要复杂的数据格式导出&#xff0c;只是在表头上略有区别&#xff0c;下面展示单行和多行表头Excel导出 1、单行表头 例如&#xff1a;Excel表头只有单行&#xff0c;那就只需要使用注解ExcelProperty即可实现 ① 添加依赖 首先&#xff0c;在 pom.xml 中添加 E…

zhidianyun01/基于 ThinkPHP+Mysql 的智慧园区+智慧园区管理系统+园区物业管理系统+园区物业管理系统源码

园区物业管理系统园区管理系统园区管理园区物业物业管理系统园区物业管理系统源码 软件架构 ThinkPHPMysql 源码合作 提供完整源代码 软件界面展示

imap发送邮件:如何配置IMAP服务器发邮件?

imap发送邮件的设置教程&#xff1f;如何使用IMAP服务发送邮件&#xff1f; IMAP发送邮件作为一种高效的邮件管理方式&#xff0c;允许用户在多个设备上同步邮件&#xff0c;极大地提升了工作效率。AokSend将详细介绍如何配置IMAP服务器以实现邮件的发送。 imap发送邮件&…

Linux入门攻坚——31、rpc概念及nfs和samba

NFS&#xff1a;Network File System 传统意义上&#xff0c;文件系统在内核中实现 RPC&#xff1a;函数调用&#xff08;远程主机上的函数&#xff09;&#xff0c;Remote Procedure Call protocol 一部分功能由本地程序完成 另一部分功能由远程主机上的 NFS本质…

通过FFmpeg和URL查看流的编码格式

FFmpeg下载后会有三个执行文件&#xff0c;跳转到FFmpeg所在文件夹 查看视频流URL地址的编码格式命令&#xff1a; // 在下载ffmpeg的文件夹中执行如下命令&#xff0c;可查看流的编码格式&#xff0c;这里的测试流是H264编码ffprobe http://devimages.apple.com/iphone/sample…

CSS学习13

CSS例子 学成网 需要使用的图片&#xff1a; 代码&#xff1a; <html><head><style>/*CSS初始化*/* { /*清除内外边框*/padding: 0;margin: 0;}ul {list-style: none; /*清除列表样式*/}.clearfix:before,.clearfix:after { /*清除浮动*/content: &qu…

C++11(1)

目录 前言 小故事 C11优势 统一的列表初始化 1.{}初始化 2. std::initializer_list 声明 1.auto 2.decltype 3.nullptr 前言 小故事 1998 年是 C 标准委员会成立的第一年&#xff0c;本来计划以后每 5 年视实际需要更新一次标准&#xff0c; C 国际 标准委员会在研究…

如何使用ChatGPT撰写研究计划书?AI写作全攻略

大家好&#xff0c;感谢关注。我是七哥&#xff0c;一个在高校里不务正业&#xff0c;折腾学术科研AI实操的学术人。关于使用ChatGPT等AI学术科研的相关问题可以和作者七哥&#xff08;yida985&#xff09;交流&#xff0c;多多交流&#xff0c;相互成就&#xff0c;共同进步&a…

从安卓开发到AI产品经理——我的AI绘画之旅

大家好&#xff0c;我是一名有着多年安卓开发经验的程序员。在日复一日的编码生活中&#xff0c;我对AI行业产生了浓厚的兴趣。于是&#xff0c;我决定转行成为一名AI产品经理。在这个过程中&#xff0c;我通过学习AI绘画工具初步了解了AI行业&#xff0c;下面我将分享我的学习…

Apache DolphinScheduler在Cisco Webex的应用与优化实践

引言 我叫李庆旺&#xff0c;是Cisco Webex的一名软件工程师&#xff0c;同时也是Apache DolphinScheduler&#xff08;以下简称DS&#xff09;的Committer。 在过去的两年里&#xff0c;公司基于Apache DolphinScheduler进行了多项持续改进和创新&#xff0c;以更好地适应我们…