题目信息
龙神觉得无聊于是来到了地下城,这里是一个巨大的迷宫,有一些可以通行的路、一些不可以通行的墙,还有一些怪物。虽然龙神可以轻易地干掉这些怪物,但他觉得这样就太没意思了,他观察到这些怪物每 k 秒会消失一次(例如 k = 3 时,则第 3, 6, 9, … ,秒怪物是消失的),每一秒龙神可以选择向上下左右行走一步(不能在原地不动)。龙神想知道在避开全部怪物的条件下,到达出口所需要的最短时间。
输入
第一行输入一个整数 T ( 1 ≤ T ≤ 10 )
,代表用例组数。
每组用例的第一行包括三个整数 n , m ( 1 ≤ n , m ≤ 100 )
和 ,k ( 1 ≤k ≤ 50 )
分别表示地下城迷宫的行数、列数、怪物的消失间隔。
接下来的 n 行代表迷宫,.
表示可以通行的路,#
表示墙,*
表示怪物,S
表示起点,E
代表出口。
输出
输出一个整数,表示龙神走出地下城迷宫的最短时间,如果龙神不能走出迷宫则输出-1。
来源
BITACM2018第一轮积分赛(三)- Problem J
测试样例
1
6 6 2
...S..
...#..
.#....
...#.#
...*..
..*E*.
7
解答
#include <iostream>
#include <queue>
using namespace std;
struct Point
{
int x;
int y;
Point(int x_, int y_) : x(x_), y(y_)
{
}
Point()
{
}
};
struct Step
{
int x;
int y;
int steps;
Step(int x_, int y_, int steps_) : x(x_), y(y_), steps(steps_)
{
}
Step()
{
}
};
int main()
{
//freopen("E://test.txt", "r", stdin);
int T;
cin >> T;
//横向的是x,即为j,均从0开始计数
while (T--)
{
int n, m, k;
cin >> n >> m >> k;
char Maze[200][200];
bool visited[110][110][50] = {
0 };
Point PointStart, PointEnd;
for (int i = 0; i < n; i++)
{
for (int j = 0; j < m; j++)
{
cin >> Maze[i][j];
if (Maze[i][j] == 'S')
{
Maze[i][j] = '.';
PointStart.x = j;
PointStart.y = i;
}
if (Maze[i][j] == 'E')
{
Maze[i][j] = '.';
PointEnd.x = j;
PointEnd.y = i;
}
}
}
//int flag = 0;
int MIN = 1<<30;
queue<Step> q;
q.push(Step(PointStart.x, PointStart.y, 0));//将第一个点压进去
while (!q.empty())
{
Step tmp = q.front();
if (tmp.y - 1 >= 0 && Maze[tmp.y - 1][tmp.x] != '#')
{
//往上走,搜索正上方的位置,首先先判断能否走过去,不被阻碍,判定成功则说明有上面这个位置可走
if ((Maze[tmp.y - 1][tmp.x] != '*') || (Maze[tmp.y - 1][tmp.x] == '*' && (tmp.steps + 1) % k == 0))
{
//上方不是*怪物,或者是*怪物但是时间恰好在间歇的时候
if (visited[tmp.y - 1][tmp.x][(tmp.steps + 1) % k] == 0)
{
//判断当前时间的情况下是否来到过,因为后面的步数都跟时间有关系
// 所以不能单单的仅凭来没来过作为判定条件,要根据当前时间以及位置的组合来
//此时是没来过的情况
if (PointEnd.x == tmp.x && PointEnd.y == tmp.y-1)
{
//终点的情况
if (tmp.steps + 1 <= MIN)
{
MIN = tmp.steps + 1;//更新最小值
//flag = 1;//标记为有答案输出
}
}
visited[tmp.y - 1][tmp.x][(tmp.steps + 1) % k] = 1;//更新过的这个点来过了
Step ReturnStep(tmp.x, tmp.y - 1, tmp.steps + 1);//压入更新过的点,步长更新
q.push(ReturnStep);
}
}
}
if (tmp.y + 1 < n && Maze[tmp.y + 1][tmp.x] != '#')
{
//往下走,搜索正下方的位置,首先先判断能否走过去,不被阻碍,判定成功则说明有下面这个位置可走
if ((Maze[tmp.y + 1][tmp.x] != '*') || (Maze[tmp.y + 1][tmp.x] == '*' && (tmp.steps + 1) % k == 0))
{
//下方不是*怪物,或者是*怪物但是时间恰好在间歇的时候
if (visited[tmp.y + 1][tmp.x][(tmp.steps + 1) % k] == 0)
{
//判断当前时间的情况下是否来到过,因为后面的步数都跟时间有关系
// 所以不能单单的仅凭来没来过作为判定条件,要根据当前时间以及位置的组合来
//此时是没来过的情况
if (PointEnd.x == tmp.x && PointEnd.y == tmp.y+1)
{
//终点的情况
if (tmp.steps + 1 <= MIN)
{
MIN = tmp.steps + 1;//更新最小值
//flag = 1;//标记为有答案输出
}
}
visited[tmp.y + 1][tmp.x][(tmp.steps + 1) % k] = 1;//更新过的这个点来过了
Step ReturnStep(tmp.x, tmp.y + 1, tmp.steps + 1);//压入更新过的点,步长更新
q.push(ReturnStep);
}
}
}
if (tmp.x - 1 >= 0 && Maze[tmp.y][tmp.x - 1] != '#')
{
//往左走,搜索左边的位置,首先先判断能否走过去,不被阻碍,判定成功则说明有左边这个位置可走
if ((Maze[tmp.y][tmp.x - 1] != '*') || (Maze[tmp.y][tmp.x - 1] == '*' && (tmp.steps + 1) % k == 0))
{
//左边不是*怪物,或者是*怪物但是时间恰好在间歇的时候
if (visited[tmp.y][tmp.x - 1][(tmp.steps + 1) % k] == 0)
{
//判断当前时间的情况下是否来到过,因为后面的步数都跟时间有关系
// 所以不能单单的仅凭来没来过作为判定条件,要根据当前时间以及位置的组合来
//此时是没来过的情况
if (PointEnd.x == tmp.x-1 && PointEnd.y == tmp.y)
{
//终点的情况
if (tmp.steps + 1 <= MIN)
{
MIN = tmp.steps + 1;//更新最小值
//flag = 1;//标记为有答案输出
}
}
visited[tmp.y][tmp.x - 1][(tmp.steps + 1) % k] = 1;//更新过的这个点来过了
Step ReturnStep(tmp.x - 1, tmp.y, tmp.steps + 1);//压入更新过的点,步长更新
q.push(ReturnStep);
}
}
}
if (tmp.x + 1 < m && Maze[tmp.y][tmp.x + 1] != '#')
{
//往右走,搜索右边的位置,首先先判断能否走过去,不被阻碍,判定成功则说明有右边这个位置可走
if ((Maze[tmp.y][tmp.x + 1] != '*') || (Maze[tmp.y][tmp.x + 1] == '*' && (tmp.steps + 1) % k == 0))
{
//右边不是*怪物,或者是*怪物但是时间恰好在间歇的时候
if (visited[tmp.y][tmp.x + 1][(tmp.steps + 1) % k] == 0)
{
//判断当前时间的情况下是否来到过,因为后面的步数都跟时间有关系
// 所以不能单单的仅凭来没来过作为判定条件,要根据当前时间以及位置的组合来
//此时是没来过的情况
if (PointEnd.x == tmp.x +1&& PointEnd.y == tmp.y)
{
//终点的情况
if (tmp.steps + 1 <= MIN)
{
MIN = tmp.steps + 1;//更新最小值
//flag = 1;//标记为有答案输出
}
}
visited[tmp.y][tmp.x + 1][(tmp.steps + 1) % k] = 1;//更新过的这个点来过了
Step ReturnStep(tmp.x + 1, tmp.y, tmp.steps + 1);//压入更新过的点,步长更新
q.push(ReturnStep);
}
}
}
q.pop();
}
if (MIN == 1 << 30)
{
cout << -1 << endl;
}
else
{
cout << MIN << endl;
}
}
}