news 2026/6/10 4:02:58

代码随想录算法训练营第四十三天:可达路径

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
代码随想录算法训练营第四十三天:可达路径

可达路径

文章讲解/视频讲解

【题目描述】

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

思路:

今天正式开始图论章节的更新,这段时间的所有题目都来源于卡码网,这是为了练习acm输入方式,没错,图论的所有题都将会是以acm输入输出方式编写,因为图的输入和输出在面试中是非常重要的环节,习惯了力扣的核心代码输出方式,面试官让你手撕就傻了眼了。

本题我们用的是dfs(深度有优先搜索),要使用深搜三部曲,其实就类似之前二叉树章节使用过的递归三部曲和回溯章节的回溯三部曲。我们先来看图的存储,有两种存储方式可选,邻接表和邻接矩阵,本题我们就用邻接矩阵来存储这个图。

邻接矩阵 使用 二维数组来表示图结构。 邻接矩阵是从节点的角度来表示图,有多少节点就申请多大的二维数组。本题我们会有n 个节点,因为节点标号是从1开始的,为了节点标号和下标对齐,我们申请 n + 1 * n + 1 这么大的二维数组。

然后再输入m个边,构造方式如下:

while (M--) { line = await readline() if (line) { [from, to] = line.split(' ').map(i => parseInt(i)) graph[from][to] = 1 } }

然后就可以开始写深搜三部曲了

1.确定递归函数及其传入参数:一共需要传入三个参数,需要搜索的图表,当前遍历的值x,遍历的重点n。

2.确定终止条件:如果我们在遍历的过程中,x === n了,说明找到了一条结果,我们就要把当前路径存入结果数组中,并且返回。

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

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

for (let i = 1; i <= n; i++) { if (graph[x][i] === 1) {

这里我们的graph数组的值为1说明可以到达

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

path.push(i)

进入下一层递归

dfs(graph, i, n); // 进入下一层递归

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

回溯这一步不必多说,之前一整个回溯章节都在使用。

最后打印结果的时候也要注意不能出错,acm模式麻烦就麻烦在这里,注意每一个结果的最后一个数字是有不能空格的,虽然看不见,好像也不影响最终结果,但是你多了个空格就是不给你过

1 3 5而不是1 3 5

即 5 的后面没有空格!

代码示例:

const r1 = require('readline').createInterface({ input: process.stdin }); // 创建readline接口 let iter = r1[Symbol.asyncIterator](); // 创建异步迭代器 const readline = async ()=>(await iter.next()).value; let graph let N, M let result = [] let path = [] async function initGraph() { let line; line = await readline(); [N, M] = line.split(' ').map(i => parseInt(i)) graph = new Array(N + 1).fill(0).map(() => new Array(N + 1).fill(0)) while (M--) { line = await readline() if (line) { [from, to] = line.split(' ').map(i => parseInt(i)) graph[from][to] = 1 } } } function dfs(graph, x, n) { if (x === n) { result.push([...path]) return } for (let i = 1; i <= n; i++) { if (graph[x][i] === 1) { path.push(i) dfs(graph, i, n) path.pop() } } } (async function () { await initGraph() path.push(1) dfs(graph, 1, N) if (result.length > 0) { result.forEach(i => { console.log(i.join(' ')) }) } else { console.log(-1) } })()
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/6/5 14:19:05

STM32CubeMX汉化环境下外设初始化代码生成解析

深入STM32CubeMX中文环境&#xff1a;外设初始化代码是如何“一键生成”的&#xff1f;你有没有经历过这样的场景&#xff1f;刚打开STM32参考手册&#xff0c;上千页的英文文档扑面而来&#xff0c;RCC_APB2ENR、GPIOx_MODER这些寄存器看得人头晕眼花。明明只是想点亮一个LED&…

作者头像 李华
网站建设 2026/6/9 20:11:23

苹果手机文件管理在测试与问题排查中的实际作用

在 iOS 生态里&#xff0c;苹果手机文件管理一直显得有些“低调”。 对普通用户来说&#xff0c;系统已经把文件藏得足够深&#xff1b; 对开发者来说&#xff0c;沙盒机制又让一切看起来井然有序。 但只要你真正参与过线上问题排查、测试回归&#xff0c;或者需要复现用户环境…

作者头像 李华
网站建设 2026/5/30 14:54:13

2025运维四大主流ITSM产品核心能力对比与选型建议

在数字化转型向纵深推进的 2025 年&#xff0c;IT 服务管理&#xff08;ITSM&#xff09;已从传统工单工具升级为连接 IT 运维与业务价值的核心枢纽。企业对 ITSM 的需求不再局限于流程流转&#xff0c;而是延伸到合规保障、生态协同、敏捷响应等多元维度。本文聚焦当前主流 IT…

作者头像 李华
网站建设 2026/5/28 20:07:37

跨平台上位机串口通信模块开发实战记录

跨平台上位机串口通信模块开发实战&#xff1a;从原理到落地的完整路径你有没有遇到过这样的场景&#xff1f;——在实验室里&#xff0c;你的Windows电脑能完美连接下位机读取数据&#xff1b;可客户一拿到Linux系统上运行&#xff0c;串口直接“失联”&#xff1b;或者macOS用…

作者头像 李华