原理
题目目标:在有向图中找到从节点1到节点n的所有可能路径,并按特定格式输出。
核心逻辑:
- 深度优先搜索(DFS):从起点(节点1)出发,递归遍历所有邻接节点,直到到达终点(节点n)。
- 路径记录与回溯:维护一个路径列表
path
,记录当前遍历路径,到达终点时将路径存入结果列表result
。 - 邻接矩阵表示图:通过二维数组
graph
存储图的连接关系,graph[s][t] = 1
表示存在边s→t
。
步骤
- 输入处理:读取节点数
n
、边数m
,构建邻接矩阵。 - 初始化路径:将起点节点1加入初始路径。
- DFS遍历:
- 从节点1开始,递归访问每个邻接节点。
- 到达终点时记录完整路径。
- 回溯时移除当前节点,继续探索其他分支。
- 结果输出:若没有路径,输出-1;否则按格式输出所有路径。
图示法表示步骤(以示例输入为例)
假设输入为:
3 3
1 2
1 3
2 3
- 邻接矩阵:
1→2, 1→3, 2→3
- DFS过程:
- 从节点1出发,探索节点2和3。
- 路径1→2→3存入结果。
- 回溯到节点1,探索节点3,路径1→3存入结果。
- 输出结果:
1 2 3 1 3
代码程序及关键行注释
#include <iostream>
#include <vector>
using namespace std;
vector<vector<int>> result; // 存储所有路径
vector<int> path; // 当前路径
// DFS遍历邻接矩阵
void dfs(const vector<vector<int>>& graph, int x, int n) {
if (x == n) { // 到达终点,记录路径
result.push_back(path);
return;
}
for (int i = 1; i <= n; i++) { // 遍历所有可能的邻接节点
if (graph[x][i] == 1) { // 存在边 x→i
path.push_back(i); // 将i加入路径
dfs(graph, i, n); // 递归深入
path.pop_back(); // 回溯,移除i
}
}
}
int main() {
int n, m, s, t;
cin >> n >> m;
vector<vector<int>> graph(n + 1, vector<int>(n + 1, 0)); // 邻接矩阵
while (m--) {
cin >> s >> t;
graph[s][t] = 1; // 标记边 s→t
}
path.push_back(1); // 初始路径包含起点
dfs(graph, 1, n); // 开始DFS遍历
if (result.empty()) cout << -1 << endl;
for (const vector<int>& pa : result) {
for (int i = 0; i < pa.size() - 1; i++) {
cout << pa[i] << " ";
}
cout << pa.back() << endl; // 输出路径的最后一个节点
}
}
时间复杂度
- 时间复杂度:O(n!),最坏情况下每个节点都与其他所有节点连接,路径数量为阶乘级别。
- 适用性:适用于小规模图(节点数≤10),但对于大规模图效率极低。
总结
- 代码优势:
- 实现简单,直接通过邻接矩阵和DFS遍历所有路径。
- 回溯机制清晰,路径记录完整。
- 潜在问题:
- 环路处理:未检查重复访问节点,若图中有环会导致无限递归(例如1→2→1循环)。
- 性能问题:路径数量可能随节点数呈指数增长,无法处理较大规模的图。
- 改进方向:
- 添加访问标记:引入
visited
数组或检查当前路径是否包含节点,避免重复访问。 - 限制路径长度:若题目要求简单路径(无重复节点),需在递归前检查节点是否已存在路径中。
- 添加访问标记:引入