1 条题解
-
0
你好!我是你的 OI 教练。
这道题(CSP-J 2024 T2 地图探险)是一道非常标准的 模拟(Simulation) 题目。
题目要求我们让机器人完全按照设定的规则移动 步,我们要做的就是把这些规则翻译成计算机代码,一步一步执行,并记下它去过多少个不同的地方。
1. 核心思路:步步为营
由于 最大只有 ,且 (数据组数)只有 5,总计算量在 左右,计算机 1 秒钟可以轻松跑完。所以我们不需要高深的算法,直接写一个循环,模拟 次操作即可。
2. 关键工具:方向数组
处理在网格图上移动的问题,最方便的方法是定义两个数组来表示方向的变化。 题目定义的坐标系是: 是行, 是列。
- (东):
- (南):
- (西):
- (北):
我们可以这样定义:
// 对应 d = 0, 1, 2, 3 int dx[4] = {0, 1, 0, -1}; int dy[4] = {1, 0, -1, 0};这样,假设当前在 ,朝向是 ,下一步的坐标 就是:
nx = x + dx[d];ny = y + dy[d];3. 数据存储与去重
- 地图存储:用
char g[1005][1005]存储输入的地图(x或.)。 - 记录去过的地方:我们需要统计有多少个不同的位置。
- 可以使用一个
bool vis[1005][1005]数组。 - 初始化全为
false(或者 0)。 - 起点的
vis[x0][y0]设为true,计数器ans初始为 1。 - 每次成功移动到一个新格子 时,检查
vis[nx][ny]:- 如果之前没来过(是
false),ans加 1,并把vis[nx][ny]标记为true。 - 如果之前来过,
ans不变,人移动过去。
- 如果之前没来过(是
- 可以使用一个
4. 模拟逻辑(循环 k 次)
每一步(循环一次)的逻辑如下:
- 计算预想的下一步位置
nx和ny。 - 检查是否合法:
- 是否越界?( 且 )
- 是否有障碍?(
g[nx][ny] == 'x')
- 分支判断:
- 情况 A(合法):
- 人真正移动过去:更新
x = nx,y = ny。 - 统计:如果这里没来过,
ans++,标记vis[nx][ny] = true。 - 朝向
d不变。
- 人真正移动过去:更新
- 情况 B(不合法):
- 人原地不动。
- 向右转:
d = (d + 1) % 4;。
- 情况 A(合法):
5. 易错点提示(坑在哪里?)
- 多组数据初始化:
- 题目有 组数据。每处理完一组,记得清空
vis数组!否则上一组的标记会影响下一组。 - 可以使用
memset(vis, 0, sizeof(vis));。
- 题目有 组数据。每处理完一组,记得清空
- 坐标越界检查顺序:
- 在判断障碍物之前,必须先判断是否越界。
- 错误写法:
if (g[nx][ny] == 'x' || nx < 1 ...)-> 这会导致数组越界访问。 - 正确写法:
if (nx >= 1 && nx <= n && ny >= 1 && ny <= m && g[nx][ny] != 'x')
- 转弯也算一步:
- 题目说了“接下来机器人将要进行 次操作”。
- 无论是“移动一步”还是“原地转弯”,都消耗一次 。不要在转弯的时候忘记循环计数。
- 1-based vs 0-based:
- 题目给的坐标是从 1 开始的。
- 建议你的数组开大一点(比如
1005),并且也从下标 1 开始存,这样逻辑最清晰,不用转换。
6. 代码结构框架
#include <iostream> #include <cstring> // 为了使用 memset using namespace std; const int MAXN = 1005; char g[MAXN][MAXN]; bool vis[MAXN][MAXN]; int dx[4] = {0, 1, 0, -1}; // 东南西北 int dy[4] = {1, 0, -1, 0}; void solve() { int n, m, k; int x, y, d; cin >> n >> m >> k; cin >> x >> y >> d; // 读入地图 for (int i = 1; i <= n; i++) { for (int j = 1; j <= m; j++) { cin >> g[i][j]; } } // 初始化访问记录 memset(vis, 0, sizeof(vis)); // 起点处理 long long ans = 1; // 起点算一个 vis[x][y] = true; // 开始模拟 k 步 while (k--) { // 1. 算出下一步想去哪 int nx = x + dx[d]; int ny = y + dy[d]; // 2. 检查能否走过去 // 条件:在地图内 且 不是障碍物 if (nx >= 1 && nx <= n && ny >= 1 && ny <= m && g[nx][ny] == '.') { // 能走:更新坐标 x = nx; y = ny; // 如果是新地方,计数 if (!vis[x][y]) { vis[x][y] = true; ans++; } } else { // 不能走:原地右转 d = (d + 1) % 4; } } cout << ans << endl; } int main() { int t; cin >> t; while (t--) { solve(); } return 0; }试着按照这个逻辑把代码补全并提交吧!加油!
- 1
信息
- ID
- 15765
- 时间
- 1000ms
- 内存
- 32MiB
- 难度
- 3
- 标签
- 递交数
- 1
- 已通过
- 1
- 上传者