地下城与勇士

题目信息

龙神觉得无聊于是来到了地下城,这里是一个巨大的迷宫,有一些可以通行的路、一些不可以通行的墙,还有一些怪物。虽然龙神可以轻易地干掉这些怪物,但他觉得这样就太没意思了,他观察到这些怪物每 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;
        }
    }
}

猜你喜欢

转载自blog.csdn.net/zhj12399/article/details/109589937