dfs回溯路径不能只用全局vector记录坐标,因为递归退回时必须撤销当前层选择,否则路径持续累积导致错误;正确做法是将path按值传递或引用+手动pop,同时visited需手动回溯。

DFS回溯路径为什么不能只靠 vector<pair>></pair> 记录坐标
因为DFS在递归退回时,必须撤销当前层的路径选择,否则上层看到的是被下层污染的路径。常见错误是用全局 path 向量 push 后不 pop,导致路径持续累积、长度爆炸或返回错误解。
正确做法是把路径作为参数传入递归函数(按值传递或引用+手动回溯),确保每层独立维护状态:
void dfs(int x, int y, vector<pair int>> path) {
path.push_back({x, y});
if (x == tx && y == ty) {
result = path; // 找到终点,保存完整路径
return;
}
for (auto [dx, dy] : directions) {
int nx = x + dx, ny = y + dy;
if (valid(nx, ny) && !visited[nx][ny]) {
visited[nx][ny] = true;
dfs(nx, ny, path); // 值传递:自动拷贝,无需 pop
visited[nx][ny] = false;
}
}
}</pair>
注意:visited 仍需手动回溯(除非用局部数组),因为它是共享状态;而 path 用值传递就天然隔离了回溯逻辑。
迷宫中遇到死路时,visited 数组怎么重置才不漏判
DFS过程中,某个方向走不通不代表整个格子无效——它可能从别的入口进来才是活路。所以不能在进入前标记 visited,而应在确认可扩展后立即标记,并在递归返回后立刻取消标记(即回溯)。
- 错误写法:在循环外统一
visited[x][y] = true,会导致该点后续无法从其他路径访问 - 正确顺序:检查合法 → 标记已访问 → 递归 → 取消标记
- 若用栈模拟非递归DFS,则需把
(x, y, step)和对应路径快照一起压栈,代价高,不推荐用于路径还原
directions 数组顺序影响结果但不影响正确性,何时需要固定顺序
上下左右({-1,0},{0,-1},{1,0},{0,1})和右下上左({0,1},{1,0},{0,-1},{-1,0})都能找到路径,但返回的**第一条可行路径**不同。如果题目要求“最短字典序路径”或 UI 上要优先显示右移,则顺序必须按题意排列。
实操建议:
- 调试阶段用固定顺序(如先右再下),方便复现行为
- 生产环境若只需任意一条解,顺序无关紧要
- 避免用
rand()打乱方向——会破坏可重现性,不利于单元测试
内存爆掉?别把 path 存成二维 vector 的 vector
有人为保存所有可行路径,定义 vector<vector>>> all_paths</vector>,并在每次到达终点时 all_paths.push_back(path)。这在迷宫稍大(比如 20×20 稀疏障碍)时极易 OOM。
更务实的做法:
- 只存一条路径(首次到达即返回),用
bool found标志提前终止递归 - 若真需全部路径,改用迭代加深 DFS(IDDFS)控制深度上限
- 路径本身用
vector<int></int>存一维索引(y * width + x)比pair节省约 8 字节/点
回溯路径的核心约束从来不是“怎么存”,而是“什么时候停”。迷宫问题里,第一个解往往就是最优解(无权图),继续搜只是浪费。
C++免费学习笔记(深入):立即使用
在学习笔记中,你将探索 C++ 的入门与实战技巧!











