代码随想录算法训练营第五十天 | 98. 所有可达路径

2024-09-05 07:52

本文主要是介绍代码随想录算法训练营第五十天 | 98. 所有可达路径,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

98. 所有可达路径

思路

图的存储

邻接矩阵

         邻接表

深度优先搜索

1.确认递归函数,参数

2.确认终止条件

3.处理目前搜索节点出发的路径

方法一: 邻接矩阵写法

方法二:邻接表写法


98. 所有可达路径

  • 题目链接:卡码网题目链接(ACM模式)
  • 文章讲解:代码随想录 

【题目描述】

给定一个有 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 <= N <= 100
  • 1 <= M <= 500

思路

图的存储

在图论理论基础篇 中我们讲到了 两种 图的存储方式:邻接表 和 邻接矩阵。

本题我们将带大家分别实现这两个图的存储方式。

邻接矩阵

邻接矩阵 使用 二维数组来表示图结构。 邻接矩阵是从节点的角度来表示图,有多少节点就申请多大的二维数组。

本题我们会有n 个节点,因为节点标号是从1开始的,为了节点标号和下标对齐,我们申请 n + 1 * n + 1 这么大的二维数组。

邻接表

邻接表 使用 数组 + 链表的方式来表示。 邻接表是从边的数量来表示图,有多少边 才会申请对应大小的链表。

邻接表的构造相对邻接矩阵难理解一些。

我在 图论理论基础篇 举了一个例子:

这里表达的图是:

  • 节点1 指向 节点3 和 节点5
  • 节点2 指向 节点4、节点3、节点5
  • 节点3 指向 节点4
  • 节点4指向节点1

我们需要构造一个数组,数组里的元素是一个链表。

深度优先搜索

本题是深度优先搜索的基础题目,关于深搜我在图论深搜理论基础 已经有详细的讲解,图文并茂。

关于本题我会直接使用深搜三部曲来分析,如果对深搜不够了解,建议先看 图论深搜理论基础。

深搜三部曲来分析题目:

1.确认递归函数,参数

首先我们dfs函数一定要存一个图,用来遍历的,需要存一个目前我们遍历的节点,定义为x。

还需要存一个n,表示终点,我们遍历的时候,用来判断当 x==n 时候 标明找到了终点。

(其实在递归函数的参数 不容易一开始就确定了,一般是在写函数体的时候发现缺什么,参加就补什么)至于 单一路径 和 路径集合 可以放在全局变量。

2.确认终止条件

什么时候我们就找到一条路径了?

当目前遍历的节点 为 最后一个节点 n 的时候 就找到了一条 从出发点到终止点的路径。

3.处理目前搜索节点出发的路径

接下来是走 当前遍历节点x的下一个节点。

首先是要找到 x节点指向了哪些节点呢? 遍历方式是这样的:

for i in range(1,n+1): # 遍历节点x链接的所有节点if graph[x][i] == 1: # 找到 x指向的节点,就是节点i

接下来就是将 选中的x所指向的节点,加入到 单一路径来。

path.append(i) # 遍历到的节点加入到路径中来

进入下一层递归

def dfs(graph, i, n) : # 进入下一层递归

最后就是回溯的过程,撤销本次添加节点的操作。

为什么要有回溯,我在图论深搜理论基础 也有详细的讲解。

方法一: 邻接矩阵写法

def dfs(graph,x,n,path,result):if x == n:result.append(path[:])returnfor i in range(1,n+1):if graph[x][i] == 1:path.append(i)dfs(graph,i,n,path,result)path.pop()def main():n,m = map(int,input().split())graph = [[0]* (n+1) for _ in range(n+1)]for i in range(m):s,t = map(int,input().split())graph[s][t] = 1result = []dfs(graph,1,n,[1],result)if not result:print(-1)else:for path in result:print(' '.join(map(str,path)))if __name__ == "__main__":main()

方法二:邻接表写法

from collections import defaultdictresult = []  # 收集符合条件的路径
path = []  # 1节点到终点的路径def dfs(graph, x, n):if x == n:  # 找到符合条件的一条路径result.append(path.copy())returnfor i in graph[x]:  # 找到 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)path.append(1)  # 无论什么路径已经是从1节点出发dfs(graph, 1, n)  # 开始遍历# 输出结果if not result:print(-1)for path in result:print(' '.join(map(str, path)))if __name__ == "__main__":main()

这篇关于代码随想录算法训练营第五十天 | 98. 所有可达路径的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1138372

相关文章

使用Java将DOCX文档解析为Markdown文档的代码实现

《使用Java将DOCX文档解析为Markdown文档的代码实现》在现代文档处理中,Markdown(MD)因其简洁的语法和良好的可读性,逐渐成为开发者、技术写作者和内容创作者的首选格式,然而,许多文... 目录引言1. 工具和库介绍2. 安装依赖库3. 使用Apache POI解析DOCX文档4. 将解析

C++使用printf语句实现进制转换的示例代码

《C++使用printf语句实现进制转换的示例代码》在C语言中,printf函数可以直接实现部分进制转换功能,通过格式说明符(formatspecifier)快速输出不同进制的数值,下面给大家分享C+... 目录一、printf 原生支持的进制转换1. 十进制、八进制、十六进制转换2. 显示进制前缀3. 指

openCV中KNN算法的实现

《openCV中KNN算法的实现》KNN算法是一种简单且常用的分类算法,本文主要介绍了openCV中KNN算法的实现,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的... 目录KNN算法流程使用OpenCV实现KNNOpenCV 是一个开源的跨平台计算机视觉库,它提供了各

使用Python实现全能手机虚拟键盘的示例代码

《使用Python实现全能手机虚拟键盘的示例代码》在数字化办公时代,你是否遇到过这样的场景:会议室投影电脑突然键盘失灵、躺在沙发上想远程控制书房电脑、或者需要给长辈远程协助操作?今天我要分享的Pyth... 目录一、项目概述:不止于键盘的远程控制方案1.1 创新价值1.2 技术栈全景二、需求实现步骤一、需求

Java中Date、LocalDate、LocalDateTime、LocalTime、时间戳之间的相互转换代码

《Java中Date、LocalDate、LocalDateTime、LocalTime、时间戳之间的相互转换代码》:本文主要介绍Java中日期时间转换的多种方法,包括将Date转换为LocalD... 目录一、Date转LocalDateTime二、Date转LocalDate三、LocalDateTim

MySQL中动态生成SQL语句去掉所有字段的空格的操作方法

《MySQL中动态生成SQL语句去掉所有字段的空格的操作方法》在数据库管理过程中,我们常常会遇到需要对表中字段进行清洗和整理的情况,本文将详细介绍如何在MySQL中动态生成SQL语句来去掉所有字段的空... 目录在mysql中动态生成SQL语句去掉所有字段的空格准备工作原理分析动态生成SQL语句在MySQL

jupyter代码块没有运行图标的解决方案

《jupyter代码块没有运行图标的解决方案》:本文主要介绍jupyter代码块没有运行图标的解决方案,具有很好的参考价值,希望对大家有所帮助,如有错误或未考虑完全的地方,望不吝赐教... 目录jupyter代码块没有运行图标的解决1.找到Jupyter notebook的系统配置文件2.这时候一般会搜索到

Python通过模块化开发优化代码的技巧分享

《Python通过模块化开发优化代码的技巧分享》模块化开发就是把代码拆成一个个“零件”,该封装封装,该拆分拆分,下面小编就来和大家简单聊聊python如何用模块化开发进行代码优化吧... 目录什么是模块化开发如何拆分代码改进版:拆分成模块让模块更强大:使用 __init__.py你一定会遇到的问题模www.

springboot+dubbo实现时间轮算法

《springboot+dubbo实现时间轮算法》时间轮是一种高效利用线程资源进行批量化调度的算法,本文主要介绍了springboot+dubbo实现时间轮算法,文中通过示例代码介绍的非常详细,对大家... 目录前言一、参数说明二、具体实现1、HashedwheelTimer2、createWheel3、n

springboot循环依赖问题案例代码及解决办法

《springboot循环依赖问题案例代码及解决办法》在SpringBoot中,如果两个或多个Bean之间存在循环依赖(即BeanA依赖BeanB,而BeanB又依赖BeanA),会导致Spring的... 目录1. 什么是循环依赖?2. 循环依赖的场景案例3. 解决循环依赖的常见方法方法 1:使用 @La