下午好🌅🌅🌅
本答案参考通义千问
你提供的代码是一个典型的 DFS(深度优先搜索) 问题,用于模拟警察在地图上寻找并抓捕小偷的过程。根据你的描述,“只对了一个测试用例”,说明你的代码 存在逻辑错误或边界条件处理不当。
✅ 一、问题分析
1. 输入读取的问题
你在读取地图时使用了 scanf("%c", &g[i][j]),但这种方式 无法正确读取换行符和空格,特别是在某些情况下,可能会导致输入数据错位,从而影响整个地图的构建。
❌ 原始代码:
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
scanf("%c", &g[i][j]);
}
getchar(); // 吸收每行末尾的换行符
}
✅ 改进方法:
使用 fgets() 或 cin.getline() 更加可靠,或者使用 scanf("%c", ...) 时注意处理空白字符。
2. DFS函数中 s 的传递方式问题
你使用的是 引用传参(int &s),但在调用 dfs(i, j, s); 时,s 是一个局部变量,每次调用都会重新初始化为 0,这会导致多次 DFS 调用之间 s 不会累加。
❌ 问题点:
int s = 0;
dfs(i, j, s);
ans += s;
- 每次调用
dfs 都是独立的,s 在每次调用后会被重置为 0。 - 但是,在
dfs 中你使用的是引用,所以 s 的值会在递归过程中被修改,这是正确的。
✅ 问题可能出现在:s 是否在递归中被正确更新?
实际上这个部分是正确的,因为 s 是引用,每次递归中修改它都会影响原始变量。
3. 标记数组的初始化问题
你使用了 memset(st, false, sizeof(st)); 来初始化 st 数组,这是正确的,但要注意:
- 如果
n 和 m 大于 105,会导致越界访问。 - 你定义的是
const int N = 105;,但输入的 n 和 m 可能超过 105,造成越界。
✅ 二、解决方案(详细步骤)
✅ 1. 修复输入读取问题
❌ 原始输入方式容易出错:
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
scanf("%c", &g[i][j]);
}
getchar();
}
✅ 推荐方式(使用 fgets):
for (int i = 0; i < n; i++) {
fgets(g[i], m + 1, stdin); // 读入一行,并保留换行符
}
注意:如果输入中有空格,应确保 fgets 正确读取。
✅ 2. 优化 DFS 函数逻辑
✅ 修改后的 DFS 函数如下:
void dfs(int x, int y, int &s) {
if (x < 0 || y < 0 || x >= n || y >= m) return;
if (g[x][y] == '#' || st[x][y]) return;
st[x][y] = true;
if (g[x][y] == '$' && !caught[x][y]) {
s++;
caught[x][y] = true;
}
dfs(x - 1, y, s);
dfs(x + 1, y, s);
dfs(x, y + 1, s);
dfs(x, y - 1, s);
}
关键改进点:将 g[x][y] == '#' 和 st[x][y] 的判断顺序调整,避免重复访问障碍物。
✅ 3. 确保全局数组大小足够
✅ 修改为动态分配(更安全):
char g[N][N];
bool st[N][N];
bool caught[N][N];
如果 n 或 m 大于 105,会导致越界。建议改为动态分配或使用 vector。
✅ 4. 主函数逻辑优化
✅ 修改后的主函数如下:
int main() {
scanf("%d%d", &n, &m);
getchar(); // 吸收换行符
for (int i = 0; i < n; i++) {
fgets(g[i], m + 1, stdin);
}
int ans = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (g[i][j] == '@') {
int s = 0;
memset(st, false, sizeof(st));
dfs(i, j, s);
ans += s;
}
}
}
printf("%d\n", ans);
return 0;
}
✅ 三、最终代码(修改后)
#include <iostream>
#include <cstring>
using namespace std;
const int N = 105;
char g[N][N];
bool st[N][N]; // 标记是否访问过
bool caught[N][N]; // 标记小偷是否被统计过
int n, m;
void dfs(int x, int y, int &s) {
if (x < 0 || y < 0 || x >= n || y >= m) return;
if (g[x][y] == '#' || st[x][y]) return;
st[x][y] = true;
if (g[x][y] == '$' && !caught[x][y]) {
s++;
caught[x][y] = true;
}
dfs(x - 1, y, s);
dfs(x + 1, y, s);
dfs(x, y + 1, s);
dfs(x, y - 1, s);
}
int main() {
scanf("%d%d", &n, &m);
getchar(); // 吸收换行符
for (int i = 0; i < n; i++) {
fgets(g[i], m + 1, stdin);
}
int ans = 0;
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
if (g[i][j] == '@') {
int s = 0;
memset(st, false, sizeof(st));
dfs(i, j, s);
ans += s;
}
}
}
printf("%d\n", ans);
return 0;
}
✅ 四、常见错误原因总结
| 问题 | 原因 | 解决方案 |
|------|------|----------|
| 输入错误 | 使用 scanf("%c", ...) 导致换行符或空格读取错误 | 改用 fgets() 或 cin.getline() |
| DFS 未正确统计 | s 没有被正确累加 | 确保 s 是引用传参,且每次调用都重新初始化 |
| 数组越界 | n 或 m 超过 N=105 | 动态分配内存或使用 vector |
| 重复访问障碍物 | 没有及时判断障碍物 | 在 DFS 开头判断是否是障碍物或已访问 |
✅ 五、测试建议
你可以尝试以下测试用例来验证程序是否正确:
测试用例 1:
3 3
@ . $
. # .
$ . @
预期输出:
2
测试用例 2:
4 4
@ . . .
. # . .
. . $ .
. . . @
预期输出:
1
如果你还有其他问题,比如“为什么还是不能 AC”或“某个测试用例失败”,可以提供具体测试数据,我可以进一步帮你调试!