当前位置: 首页 > news >正文

图论 | part01

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 <= N <= 100
  • 1 <= M <= 500
public class Main { public static List<Integer> path = new ArrayList<>(); public static List<List<Integer>> res = new ArrayList<>(); public static void main(String[] args) { Scanner scanner = new Scanner(System.in); if (!scanner.hasNext()) return; // 防止空输入 int n = scanner.nextInt(); int m = scanner.nextInt(); int[][] graph = new int[n + 1][n + 1]; for (int i = 0; i < m; i++) { int s = scanner.nextInt(); int t = scanner.nextInt(); graph[s][t] = 1; } path.add(1); dfs(graph, 1, n); if (res.isEmpty()) { System.out.println(-1); } else { for (List<Integer> list : res) { for (int i = 0; i < list.size(); i++) { System.out.print(list.get(i)); if (i != list.size() - 1) { System.out.print(" "); } } System.out.println(); } } } public static void dfs(int[][] graph, int now, int end) { if (now == end) { res.add(new ArrayList<>(path)); return; } // 遍历所有可能的下一个节点 (1 到 n) for (int i = 1; i <= end; i++) { // 确保不越界,虽然上面修正了数组大小,但逻辑上 i 最大也就是 n if (graph[now][i] == 1) { path.add(i); dfs(graph, i, end); path.remove(path.size() - 1); // 回溯 } } } }

解题:

本题使用的是深度优先搜索方法

  1. 输入处理
    • 读取节点数 NN和边数 MM
    • 使用二维数组int[][] graph = new int[n + 1][n + 1]构建邻接矩阵graph[s][t] = 1表示存在一条从节点 ss指向节点 tt的有向边。
    • 注意:数组大小设为 N+1N+1 是为了方便直接使用 1-based 的节点编号,避免索引转换。
  1. 初始化搜索
    • path.add(1);:将起点 1 加入当前路径。
    • dfs(graph, 1, n);:从节点 1 开始进行深度优先搜索,目标是节点 NN
  1. 结果输出
    • 检查res是否为空。
    • 如果为空,说明没有找到任何路径,输出-1
    • 如果不为空,遍历res中的每一条路径,按格式打印(节点间空格分隔,行末无空格)。

在DFS中

  • 终止条件:当now == end时,说明已经成功走到终点。此时将path的一个新副本new ArrayList<>(path))加入结果集res。必须新建副本,因为path对象在后续回溯中会被修改。
  • 遍历邻居:循环检查从 1 到 NN的所有节点i
  • 剪枝/判断if (graph[now][i] == 1)确保只沿着存在的有向边走。
  • 回溯机制
    1. path.add(i):进入下一层递归前,记录当前步骤。
    2. dfs(...):深入探索。
    3. path.remove(...):当递归返回(无论是找到终点还是无路可走),需要把最后加入的节点移除,恢复到进入该分支前的状态,以便尝试下一个可能的邻居节点。这是解决“所有路径”问题的关键。
http://www.jsqmd.com/news/464043/

相关文章:

  • 从与非门到2位加法器:在多思平台玩转计算机组成原理实验
  • 【行恒科技设备助力科研】纳米气泡-氧化石墨烯复合膜, NBs-GO膜高效截留染料废水研究!
  • SAP邮件附件优化指南:如何用SMARTFORMS生成小于5MB的PDF文件
  • Visual Studio 2010实战:构建高效Windows窗体应用程序的完整指南
  • 从零搭建智能火车票查询系统:Dify+MCP+高德地图全栈教程
  • 基于51单片机的便携式健康监测仪设计与实现【附仿真、源码与详解】
  • OAI 5G核心网与基站一体化部署实战:从源码到商用终端入网全解析
  • 为什么要在 Ubuntu 22.04 上手动安装 GCC 12.2?系统自带版本不够用吗?
  • LiDAR-IMU联合初始化代码解析:从ROS参数读取到点云畸变矫正全流程
  • Spring Cloud Gateway + 请求聚合(GraphQL-like):一次调用合并多个微服务响应
  • Go中的Tcp编程为什么总是能看到handle?
  • STM32F4寄存器操作实战:从宏定义到结构体的两种高效访问方式
  • 从2D到3D感知:四大前沿模型如何重塑视觉语言模型的空间理解能力
  • Cursor AI编辑器实战:5个隐藏功能让你的开发效率翻倍(附配置技巧)
  • STM32CubeIDE实战:从零构建高效嵌入式开发工作流
  • 技术演进与挑战:深度学习驱动下的三维重建方法全景解析
  • java写用户登陆注册
  • 基于网格搜索与分段回归的时间序列变化点检测方法
  • 2026年 凸轮机数控系统/数控集成方案厂家推荐榜单:高精度智能控制与定制化解决方案深度解析 - 品牌企业推荐师(官方)
  • Obsidian入门指南 —— 从零开始构建个人知识库
  • Python wordcloud安装避坑指南:不用装Visual C++也能搞定(附whl文件下载)
  • 哈工大Linux0.11实验环境搭建保姆级教程(附GitHub源码解析)
  • Remotion 是什么?
  • OpenClaw 多 Agent 协作:一个人管理 5 个 AI 员工
  • 深入解析dpkg-architecture:Debian系统架构管理的利器
  • 高速数字电路阻抗匹配实战:从默认值到精准设计的跨越
  • AgenticOCR 实战教程(非常详细),视觉 RAG 复杂文档解析从入门到精通,收藏这一篇就够了!
  • 利用Arcpy实现ArcGIS中多字段批量克里金与反距离权重插值的高效自动化
  • 机器人工程师必备:用Graphviz把URDF变成精美PDF图纸的3种姿势
  • 告别virt-manager:Flint如何用11MB二进制重塑KVM管理体验?