zoukankan      html  css  js  c++  java
  • CDOJ_149 解救小Q

    原题网址:http://acm.uestc.edu.cn/#/problem/show/149

    小Q被邪恶的大魔王困在了迷宫里,love8909决定去解救她。 迷宫里面有一些陷阱,一旦走到陷阱里,就会被困身亡:(,迷宫 里还有一些古老的传送

    阵,一旦走到传送阵上,会强制被传送到 传送阵的另一头。

    现在请你帮助love8909算一算,他至少需要走多少步才能解 救到小Q?

    Input

    第一行为一个整数T,表示测试数据组数。

    每组测试数据第一行为两个整数NM,(1N,M50)表示 迷宫的长和宽。

    接下来有N行,每行M个字符,是迷宫的具体描述。

    • .表示安全的位置
    • #表示陷阱,
    • Q表示小Q的位置
    • L表示love8909所在位置,

    数据保证love8909只有一个,数据也保证小Q只有一个。

    小写字母a-z表示分别表示不同的传送阵,数据保证传送阵 两两配对。

    Output

    每组数据输出一行,解救小Q所需的最少步数,如果无论如何都 无法救小Q,输出-1

    Sample input and output

    Sample Input Sample Output
    2
    
    5 5
    ....L
    .###.
    b#b#a
    ##.##
    ...Qa
    
    5 5
    ....L
    .###.
    .#.#.
    ##.##
    ...Q.
    3
    -1
    这道题采用广度优先搜索,每走过一个地方计算这个地方离起点的距离,并将这个点加入队列。不过要注意的是对应传送门的深度是相同的。为方便
    处理,在输入的时候就将传送门的对应关系建立好。另外需要注意的是,在传送时,只能将传送门的一头标记为已访问,因为可能最短路是从另一头
    传送过来的(传送门是双向的)。
    好了,废话少说,献上代码。
    #include<iostream>
    #include<queue>
    #include<string.h>
    #define MAX_N 50
    #define MAX_M 50
    #define INF 3000
    using namespace std;
    
    typedef pair<int, int> P;
    char maze[MAX_N + 5][MAX_M + 5];//迷宫
    int d[MAX_N + 5][MAX_M + 5];//表示离起点的距离
    int dx[4] = { 0, 1, 0, -1 };
    int dy[4] = { 1, 0, -1, 0 };
    P door[MAX_N + 5][MAX_M + 5];//储存传送门的对应关系
    bool flag[MAX_N + 5][MAX_M + 5];//记录节点是否被访问过
    int lx, ly, qx, qy;
    int N, M;
    
    void input()
    {
        P temp[28];
        cin >> N >> M;
        fill(temp, temp + 28, P(INF, INF));
        for (int i = 0; i < N; i++)
            for (int j = 0; j < M; j++)
                door[i][j].first = door[i][j].second = INF;
        for (int i = 0; i < N; i++)
            for (int j = 0; j < M; j++)
            {
                char m;
                cin >> m;
                maze[i][j] = m;
                if (m >= 'a' && m <= 'z')
                {
                    if (temp[m - 'a'] == P(INF, INF))//传送门第一次出现
                        temp[m - 'a'] = P(i, j);
                    else//传送门已经出现过了
                    {
                        door[i][j] = P(temp[m - 'a'].first, temp[m - 'a'].second);
                        door[temp[m - 'a'].first][temp[m - 'a'].second] = P(i, j);
                    }
                }
                else if (m == 'L'){lx = i; ly = j; maze[i][j] = '#';}
                else if (m == 'Q'){ qx = i; qy = j; }
            }
    }
    
    int bfs()
    {
        memset(flag, 0, sizeof(flag));
        for (int i = 0; i < N; i++)
            for (int j = 0; j < M; j++)
                d[i][j] = INF;
        queue<P> que;
        que.push(P(lx, ly));//将起点加入队列
        d[lx][ly] = 0;//并将起点的距离赋为0
        while (!que.empty())//不断循环,知道队列为空
        {
            int nx, ny;
            P now = que.front();//当前节点
            que.pop();
            if (now.first == qx&&now.second == qy)
                break;
            for (int i = 0; i < 4; i++)//向四个方向遍历
            {
                nx = now.first + dx[i];
                ny = now.second + dy[i];
                if (nx < N && nx >= 0 && ny < M && ny >= 0 && !flag[nx][ny])//未超边界,且未访问过
                {
                    if (maze[nx][ny] <= 'z'&&maze[nx][ny] >= 'a')//传送门
                    {
                        int dnow = d[now.first][now.second];
                        d[door[nx][ny].first][door[nx][ny].second] = dnow + 1;//传送
                        que.push(P(door[nx][ny].first, door[nx][ny].second));//将传送后的节点加入队列
                    }
                    else if (maze[nx][ny] != '#')//不是传送门
                    {
                        d[nx][ny] = d[now.first][now.second] + 1;
                        que.push(P(nx, ny));
                    }
                    flag[nx][ny] = 1;//将节点标记为访问过
                }
            }
        }
        return d[qx][qy];
    }
    
    int main()
    {
        int T;
        cin >> T;
        for (int t = 0; t < T; t++)
        {
            input();
            int res = bfs();
            cout << (res == INF ? -1 : res);
            if (t < T - 1)
                cout << endl;
        }
        return 0;
    }



  • 相关阅读:
    C++中的explicitkeyword
    SQLite数据库查看工具(免费)
    C Tricks(十九)—— 求以任意数为底的对数
    分治法(divide & conquer)与动态规划(dynamic programming)应用举例
    分治法(divide & conquer)与动态规划(dynamic programming)应用举例
    C++组合数(combination)的实现
    C++组合数(combination)的实现
    算法求解方法与思路的总结
    算法求解方法与思路的总结
    使用 STL 辅助解决算法问题
  • 原文地址:https://www.cnblogs.com/HarryGuo2012/p/4524053.html
Copyright © 2011-2022 走看看