【C++ 代码分析与重构】常见 DFS 逻辑错误解析与修正
1. 原代码问题分析
给出的 DFS 代码存在多处编译错误 与逻辑缺陷,总结如下:
-
语法与编译错误:
- 数组定义越界 :
dx和dy数组定义为了int dx[4][4],应改为一维数组int dx[4]。 - 变量未定义 :在
dfs函数中使用了未声明的变量n、nx、ny。 - 函数返回值丢失 :声明为
long long dfs()但部分分支没有返回值。
- 数组定义越界 :
-
逻辑与算法错误:
- 方向遍历缺失 :代码没有使用
for循环遍历上下左右四个方向。 - 状态回溯与累加错误 :
res设为了全局变量并在多处混用,导致递归搜索路径上的点权累积错乱。 - 坐标基准不一致 :主函数读入矩阵时使用的是 0-based 索引(
0到n-1),但在调用dfs时传入了dfs(1, 1),且终点判断为x == n && y == n,导致起点终点坐标对不上。 - 访问标记逻辑颠倒 :
if校验条件中写了visited[nx][ny](已访问过才进入),应为!visited[nx][ny](未访问才进入)。
- 方向遍历缺失 :代码没有使用
2. 正确代码实现(记忆化搜索 / 深度优先搜索)
假设题目需求为:从左上角出发,在矩阵中按规则寻找一条路径,使沿途经过的点权之和最大。
以下是修复并优化后的完整代码:
cpp
#include <bits/stdc++.h>
using namespace std;
const int MAXN = 1005;
int grid[MAXN][MAXN];
bool visited[MAXN][MAXN];
int n, m;
// 方向数组:上、右、下、左
int dx[4] = {-1, 0, 1, 0};
int dy[4] = {0, 1, 0, -1};
// dfs 返回从 (x, y) 出发能获得的最大点权和
long long dfs(int x, int y) {
// 到达终点 (n-1, m-1)
if (x == n - 1 && y == m - 1) {
return grid[x][y];
}
long long max_sub_res = 0;
visited[x][y] = true;
// 遍历 4 个方向
for (int i = 0; i < 4; i++) {
int nx = x + dx[i];
int ny = y + dy[i];
// 边界检查、未访问检查、合法格子检查
if (nx >= 0 && nx < n && ny >= 0 && ny < m && !visited[nx][ny] && grid[nx][ny] != 0) {
max_sub_res = max(max_sub_res, dfs(nx, ny));
}
}
visited[x][y] = false; // 回溯恢复现场
return grid[x][y] + max_sub_res;
}
int main() {
// 提高读写效率
ios::sync_with_stdio(false);
cin.tie(nullptr);
if (!(cin >> n >> m)) return 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
cin >> grid[i][j];
}
}
// 从起点 (0, 0) 开始搜索
long long ans = dfs(0, 0);
cout << ans << "\n";
return 0;
}
3. 关键修正对比表
| 修改项 | 原代码问题 | 修正方法 |
|---|---|---|
| 方向数组 | int dx[4][4] |
改为 int dx[4] = {-1, 0, 1, 0} |
| 坐标基准 | 输入用 0 到 n-1,搜索用 1 到 n |
统一使用 0-based 坐标,起点 (0, 0),终点 (n-1, m-1) |
| 访问条件 | visited[nx][ny] |
改为 !visited[nx][ny] |
| 路径递归 | 缺少对四个方向的 for 循环遍历 |
添加 for (int i = 0; i < 4; i++) |
| 返回值处理 | 直接修改全局 res 导致逻辑混淆 |
采用自底向上的递归返回值 grid[x][y] + max_sub_res |