P11228 [CSP-J 2024] 地图探险
题目描述
小 A 打算前往一片丛林去探险。丛林的地理环境十分复杂,为了防止迷路,他先派遣了一个机器人前去探路。
丛林的地图可以用一个 nnn 行 mmm 列的字符表来表示。我们将第 iii 行第 jjj 列的位置的坐标记作 (i,j)(1≤i≤n(i, j)(1 \leq i \leq n(i,j)(1≤i≤n,1≤j≤m)1 \leq j \leq m)1≤j≤m)。如果这个位置的字符为 x\tt xx,即代表这个位置上有障碍,不可通过。反之,若这个位置的字符为 .\tt..,即代表这个位置是一片空地,可以通过。
这个机器人的状态由位置和朝向两部分组成。其中位置由坐标 (x,y)(1≤x≤n(x, y)(1 \leq x \leq n(x,y)(1≤x≤n,1≤y≤m)1 \leq y \leq m)1≤y≤m) 刻画,它表示机器人处在地图上第 xxx 行第 yyy 列的位置。而朝向用一个 0∼30 \sim 30∼3 的整数 ddd 表示,其中 d=0d = 0d=0 代表向东,d=1d = 1d=1 代表向南,d=2d = 2d=2 代表向西,d=3d = 3d=3 代表向北。
初始时,机器人的位置为 (x0,y0)(x_0, y_0)(x0,y0),朝向为 d0d_0d0。保证初始时机器人所在的位置为空地。接下来机器人将要进行 kkk 次操作。每一步,机器人将按照如下的模式操作:
-
假设机器人当前处在的位置为 (x,y)(x, y)(x,y),朝向为 ddd。则它的方向上的下一步的位置 (x′,y′)(x^′, y^′)(x′,y′) 定义如下:若 d=0d = 0d=0,则令 (x′,y′)=(x,y+1)(x^′, y^′) = (x, y + 1)(x′,y′)=(x,y+1),若 d=1d = 1d=1,则令 (x′,y′)=(x+1,y)(x^′, y^′) = (x + 1, y)(x′,y′)=(x+1,y),若 d=2d = 2d=2,则令 (x′,y′)=(x,y−1)(x^′, y^′) = (x, y - 1)(x′,y′)=(x,y−1),若 d=3d = 3d=3,则令 (x′,y′)=(x−1,y)(x^′, y^′) = (x - 1, y)(x′,y′)=(x−1,y)。
-
接下来,机器人判断它下一步的位置是否在地图内,且是否为空地。具体地说,它判断 (x′,y′)(x^′, y^′)(x′,y′) 是否满足 1≤x′≤n,1≤y′≤m1 \leq x^′ \leq n, 1 \leq y^′ \leq m1≤x′≤n,1≤y′≤m,且 (x′,y′)(x^′, y^′)(x′,y′) 位置上是空地。如果条件成立,则机器人会向前走一步。它新的位置变为 (x′,y′)(x^′, y^′)(x′,y′),且朝向不变。如果条件不成立,则它会执行“向右转”操作。也就是说,令 d′=(d+1) mod 4d^′ = (d + 1) \bmod 4d′=(d+1)mod4(即 d+1d + 1d+1 除以 444 的余数),且它所处的位置保持不变,但朝向由 ddd 变为 d′d^′d′。
小 A 想要知道,在机器人执行完 kkk 步操作之后,地图上所有被机器人经过的位置(包括起始位置)有几个。
输入格式
本题有多组测试数据。
输入的第一行包含一个正整数 TTT,表示数据组数。
接下来包含 TTT 组数据,每组数据的格式如下:
第一行包含三个正整数 n,m,kn, m, kn,m,k。其中 n,mn, mn,m 表示地图的行数和列数,kkk 表示机器人执行操作的次数。
第二行包含两个正整数 x0,y0x_0, y_0x0,y0 和一个非负整数 d0d_0d0。
接下来 nnn 行,每行包含一个长度为 mmm 的字符串。保证字符串中只包含 x\tt{x}x 和 .\tt{.}. 两个字符。其中,第 xxx 行的字符串的第 yyy 个字符代表的位置为 (x,y)(x, y)(x,y)。这个位置是 x\tt{x}x 即代表它是障碍,否则代表它是空地。数据保证机器人初始时所在的位置为空地。
输出格式
对于每组数据:输出一行包含一个正整数,表示地图上所有被机器人经过的位置(包括起始位置)的个数。
输入输出样例 #1
输入 #1
2
1 5 4
1 1 2
....x
5 5 20
1 1 0
.....
.xxx.
.x.x.
..xx.
x....
输出 #1
3
13
说明/提示
【样例 1 解释】
该样例包含两组数据。对第一组数据,机器人的状态以如下方式变化:
- 初始时,机器人位于位置 (1,1)(1, 1)(1,1),方向朝西(用数字 222 代表)。
- 第一步,机器人发现它下一步的位置 (1,0)(1, 0)(1,0) 不在地图内,因此,它会执行“向右转”操作。此时,它的位置仍然为 (1,1)(1, 1)(1,1),但方向朝北(用数字 333 代表)。
- 第二步,机器人发现它下一步的位置 (0,1)(0, 1)(0,1) 不在地图内,因此,它仍然会执行“向右转”操作。此时,它的位置仍然为 (1,1)(1, 1)(1,1),但方向朝东(用数字 000 代表)。
- 第三步,机器人发现它下一步的位置 (1,2)(1, 2)(1,2) 在地图内,且为空地。因此,它会向东走一步。此时,它的位置变为 (1,2)(1, 2)(1,2),方向仍然朝东。
- 第四步,机器人发现它下一步的位置 (1,3)(1, 3)(1,3) 在地图内,且为空地。因此,它会向东走一步。此时,它的位置变为 (1,3)(1, 3)(1,3),方向仍然朝东。
因此,四步之后,机器人经过的位置有三个,分别为 (1,1),(1,2),(1,3)(1, 1),(1, 2),(1, 3)(1,1),(1,2),(1,3)。
对第二组数据,机器人依次执行的操作指令为:向东走到 (1,2)(1, 2)(1,2),向东走到 (1,3)(1, 3)(1,3),向东走到 (1,4)(1, 4)(1,4),向东走到 (1,5)(1, 5)(1,5),向右转,向南走到 (2,5)(2, 5)(2,5),向南走到 (3,5)(3, 5)(3,5),向南走到 (4,5)(4, 5)(4,5),向南走到 (5,5)(5, 5)(5,5),向右转,向西走到 (5,4)(5, 4)(5,4),向西走到 (5,3)(5, 3)(5,3),向西走到 (5,2)(5, 2)(5,2),向右转,向北走到 (4,2)(4, 2)(4,2),向右转,向右转,向南走到 (5,2)(5, 2)(5,2),向右转,向右转。
【样例 2】
见选手目录下的 explore/explore2.in 与 explore/explore2.ans。
该样例满足第 3∼43\sim 43∼4 个测试点的限制条件。
【样例 3】
见选手目录下的 explore/explore3.in 与 explore/explore3.ans。
该样例满足第 555 个测试点的限制条件。
【样例 4】
见选手目录下的 explore/explore4.in 与 explore/explore4.ans。
该样例满足第 666 个测试点的限制条件。
【样例 5】
见选手目录下的 explore/explore5.in 与 explore/explore5.ans。
该样例满足第 8∼108 \sim 108∼10 个测试点的限制条件。
【数据范围】
对于所有测试数据,保证:1≤T≤51 \leq T \leq 51≤T≤5,1≤n,m≤1031 \leq n, m \leq 10^31≤n,m≤103,1≤k≤1061 \leq k \leq 10^61≤k≤106,1≤x0≤n1 \leq x_0 \leq n1≤x0≤n,1≤y0≤m1 \leq y_0 \leq m1≤y0≤m,0≤d0≤30 \leq d_0 \leq 30≤d0≤3,且机器人的起始位置为空地。
::cute-table{tuack}
| 测试点编号 | nnn | mmm | kkk | 特殊性质 |
|---|---|---|---|---|
| 111 | =1=1=1 | ≤2\leq 2≤2 | =1=1=1 | 无 |
| 222 | ^ | ^ | ^ | ^ |
| 333 | ≤102\leq 10^2≤102 | ≤102\leq 10^2≤102 | ^ | ^ |
| 444 | ^ | ^ | ^ | ^ |
| 555 | =1=1=1 | ≤103\leq 10^3≤103 | ≤2×103\leq 2\times 10^3≤2×103 | 地图上所有位置均为空地 |
| 666 | ^ | ^ | ^ | 无 |
| 777 | ≤103\leq 10^3≤103 | ^ | ≤106\leq 10^6≤106 | 地图上所有位置均为空地 |
| 888 | ^ | ^ | ^ | 无 |
| 999 | ^ | ^ | ^ | ^ |
| 101010 | ^ | ^ | ^ | ^ |
为了解决这个问题,我们需要模拟机器人在给定地图上的移动过程,并统计所有被访问过的不同位置的数量(包括起始位置)。机器人的移动规则包括向前移动或向右转弯,具体取决于下一步位置是否可通行。由于移动步数可能很大,我们需要检测循环状态以避免不必要的计算。
方法思路
- 初始化:读取输入数据,包括地图大小、步数、起始位置和方向,以及地图本身。
- 状态跟踪:使用两个数组来跟踪已访问的位置和已出现的状态(位置和方向组合)。
- 模拟移动:对于每一步操作,计算机器人的下一步位置。如果下一步位置有效且可通行,则移动;否则,向右转弯。
- 循环检测:在每一步后检查当前状态(位置和方向)是否之前出现过。如果出现过,说明进入循环,后续步骤不会访问新位置,提前终止模拟。
- 统计结果:在模拟过程中记录所有访问过的位置,最终输出不同位置的数量。
解决代码
#include <iostream>
#include <cstring> // 用于memset函数
using namespace std;
const int MAX_N = 1005; // 最大地图行数
const int MAX_M = 1005; // 最大地图列数
int main() {
int T; // 测试数据组数
cin >> T;
while (T--) {
int n, m, k; // 地图行数、列数、操作次数
cin >> n >> m >> k;
int x0, y0, d0; // 初始位置和朝向
cin >> x0 >> y0 >> d0;
char grid[MAX_N][MAX_M]; // 存储地图
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
cin >> grid[i][j];
}
}
// 调整坐标从1-based到0-based(内部处理)
int x = x0 - 1;
int y = y0 - 1;
int d = d0;
// 方向向量:东、南、西、北
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
// 记录位置是否被访问过
bool visited[MAX_N][MAX_M] = {false};
// 记录状态(x,y,d)是否出现过,用于检测循环
bool state_visited[MAX_N][MAX_M][4] = {false};
// 初始化起始位置
visited[x][y] = true;
int count = 1; // 记录访问过的不同位置数量
// 模拟k次操作
for (int step = 0; step < k; step++) {
// 计算下一步的位置
int nx = x + dx[d];
int ny = y + dy[d];
// 检查下一步是否有效(在地图范围内且不是障碍)
if (nx >= 0 && nx < n && ny >= 0 && ny < m && grid[nx+1][ny+1] == '.') {
// 有效移动:更新位置,方向不变
x = nx;
y = ny;
// 如果这个位置是第一次访问,增加计数
if (!visited[x][y]) {
visited[x][y] = true;
count++;
}
} else {
// 无效移动:向右转(方向+1模4)
d = (d + 1) % 4;
}
// 检查当前状态是否已经出现过(检测循环)
if (state_visited[x][y][d]) {
// 如果状态重复,说明进入循环,后续操作不会访问新位置
// 可以提前结束模拟
break;
}
// 标记当前状态为已访问
state_visited[x][y][d] = true;
}
// 输出结果:访问过的不同位置数量
cout << count << endl;
}
return 0;
}
代码解释
- 输入处理:读取测试用例数量
T,对于每个测试用例,读取地图尺寸n、m和步数k,以及起始位置x0、y0和方向d0。 - 地图存储:将地图存储为字符串向量
grid,其中每个字符串代表一行地图数据。 - 方向移动:使用
dx和dy数组定义东、南、西、北四个方向的移动增量。 - 访问跟踪:使用
vis_pos跟踪已访问的位置,vis_state跟踪已出现的状态(位置和方向组合)。 - 模拟循环:对于每一步,计算下一步位置。如果有效则移动,否则转弯。更新访问位置和状态,检测循环并提前终止。
- 结果输出:输出访问过的不同位置数量
cnt。
1500

被折叠的 条评论
为什么被折叠?



