图论 | 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 path = new ArrayList<>();
    public static List<List> 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(...):当递归返回(无论是找到终点还是无路可走),需要把最后加入的节点移除,恢复到进入该分支前的状态,以便尝试下一个可能的邻居节点。这是解决"所有路径"问题的关键。
相关推荐
土司大王3 小时前
LeetCode hot100——对称二叉树
算法·leetcode·职场和发展
sali-tec4 小时前
C# 基于OpenCv的视觉工作流-章106-差值追踪
图像处理·人工智能·opencv·算法·计算机视觉
Navigator_Z4 小时前
LeetCode //C - 1208. Get Equal Substrings Within Budget
c语言·算法·leetcode
手写码匠4 小时前
Dify 多 Agent 工具权限与安全沙箱实战:让智能体“有能力,但不越权“
人工智能·深度学习·算法·aigc
黎阳之光4 小时前
打破堆场感知黑盒:黎阳之光视频孪生,构建港口码头网格化透明管控新体系
大数据·人工智能·算法·安全·数字孪生
大模型码小白5 小时前
AI 对话流性能调优:万级消息的虚拟滚动落地
java·大数据·前端·javascript·人工智能·算法·机器学习
sel_96 小时前
【多轮对话论文导读(三)】多轮对话与Agent论文阅读笔记:用户模拟、轨迹生成与长期记忆
论文阅读·人工智能·笔记·深度学习·算法·机器学习
Asize6 小时前
438. 找到字符串中所有字母异位词
算法
Asize6 小时前
283. 移动零
算法
船厂电气自动化ai大模型8 小时前
AI大模型与数学·第57课 傅里叶全套工具链综合实战:串联级数/连续变换/DFT/FFT,图像、音频、扩散模型完整例题
数据结构·人工智能·深度学习·算法·机器学习