• P1825 [USACO11OPEN]Corn Maze S


    P1825 [USACO11OPEN]Corn Maze S

    标记还是不标记?这是个问题.

    直接看得出来是bfs,只不过遇到传送装置要特殊处理.

    最初的想法是,每当遍历到一个为传送门的新格子时,而该格子本身不标记,将该格子传送到的格子标记为visited.在这个基础上就可以当作普通bfs来做了.

    结果是WA和AC参半.这样做的漏洞在于使得一个传送装置只能单向传送一次,而这是会漏解的,如:

    #####.#
    #@A=#A#
    #######

    →↑↓→即可到达终点,而上述做法导致此情况无解.

    正确的方法是遇到传送装置时标记该格子,而不标记传送到的格子.在这个基础上当成普通bfs即可AC,

    #include <algorithm>
    #include <cstdio>
    #include <cstring>
    #include <iostream>
    #include <queue>
    using namespace std;
    
    int n, m, sx, sy, fx, fy;
    int trans[30][2][2];
    int dx[4] = {0, 0, -1, 1}, dy[4] = {-1, 1, 0, 0};
    char s[310][310];
    bool vis[310][310];
    struct S {
        int x, y, t;
    };
    queue<struct S> que;
    
    int main() {
        // freopen("out.txt", "w", stdout);
        // freopen("in.txt", "r", stdin);
        char tmp;
        cin >> n >> m;
        for (int i = 0; i < n; i++)
            for (int j = 0; j < m; j++) {
                cin >> tmp;
                if (tmp == '@') {
                    sx = i;
                    sy = j;
                } else if (tmp == '=') {
                    fx = i;
                    fy = j;
                } else if (tmp != '#' && tmp != '.') {
                    if (!trans[tmp - 'A'][0][0]) {
                        trans[tmp - 'A'][0][0] = i;
                        trans[tmp - 'A'][0][1] = j;
                    } else {
                        trans[tmp - 'A'][1][0] = i;
                        trans[tmp - 'A'][1][1] = j;
                    }
                }
                s[i][j] = tmp;
            }
    
        que.push({sx, sy, 0});
        vis[sx][sy] = true;
        while (!que.empty()) {
            struct S p = que.front();
            que.pop();
    
            if (p.x == fx && p.y == fy) {
                printf("%d
    ", p.t);
                break;
            }
    
            for (int i = 0; i < 4; i++) {
                int nx = p.x + dx[i], ny = p.y + dy[i];
                if (nx >= 0 && nx < n && ny >= 0 && ny < m && s[nx][ny] != '#' && !vis[nx][ny]) {
                    if (s[nx][ny] == '.' || s[nx][ny] == '=') {
                            que.push({nx, ny, p.t + 1});
                            // printf("!!!(%d,%d) %d
    ", nx, ny, p.t + 1);
                            vis[nx][ny] = true;
                    } else {  // transport
                        vis[nx][ny] = true;
                        int ind = s[nx][ny] - 'A';
                        if (trans[ind][0][0] == nx && trans[ind][0][1] == ny) {
                            nx = trans[ind][1][0];
                            ny = trans[ind][1][1];
                        } else {
                            nx = trans[ind][0][0];
                            ny = trans[ind][0][1];
                        }
                        // if (!vis[nx][ny]) {
                            que.push({nx, ny, p.t + 1});
                            // printf("!!!(%d,%d) %d
    ", nx, ny, p.t + 1);
                            // vis[nx][ny] = true;
                        // }
                    }
                }
            }
        }
    
        return 0;
    }
    View Code

     此外,实践表明如果遇到传送门时不对任何格子做标记,也不检测目标格子是否已经标记而直接push到队列里面的话仍然可以AC.此时可以想象到队列里面有几个点传送来传送去,他们的step不断递增并且不会跳出这个循环,并不会对结果产生影响,只是让搜索的效率有所下降,这样的点越多效率损耗越大.

    这道题最多只有26个传送门,所以照常AC了.

    所以说如果实在不确定(懒得想)标记与否,可以牺牲一点效率换取稳定性.

     
  • 相关阅读:
    AJAX传输图片文件
    和内嵌的iframe进行通讯
    ts的特殊数据类型
    Angular RxJs:针对异步数据流编程工具
    Angular路由使用
    RBAC基于角色的权限管理模型
    Java中的实体类--Serializable接口、transient 关键字
    字符串问题----将整数字符串转换成整数值
    字符串问题----判断两个字符串是否互为旋转词
    字符串问题----去掉字符串中连续出现K个0的子串
  • 原文地址:https://www.cnblogs.com/Gaomez/p/14056700.html
Copyright © 2020-2023  润新知