3046: 【普及+/提高】【P1363】幻象迷宫

内存限制:128 MB 时间限制:1.000 S
评测方式:文本比较 命题人:
提交:8 解决:4

题目描述

幻象迷宫可以认为是无限大的,不过它由若干个N*M的矩阵重复组成。矩阵中有的地方是道路,用'.'表示;有的地方是墙,用'#'表示。LHX和WD所在的位置用'S'表示。也就是对于迷宫中的一个点(x,y),如果(x mod n,y mod m)是'.'或者'S',那么这个地方是道路;如果(x mod n,y mod m)是'#',那么这个地方是墙。LHX和WD可以向上下左右四个方向移动,当然不能移动到墙上。

请你告诉LHX和WD,它们能否走出幻象迷宫(如果它们能走到距离起点无限远处,就认为能走出去)。如果不能的话,LHX就只好启动城堡的毁灭程序了……当然不到万不得已,他不想这么做。。。

输入

输入包含多组数据,以EOF结尾。

每组数据的第一行是两个整数N、M。

接下来是一个N*M的字符矩阵,表示迷宫里(0,0)到(n-1,m-1)这个矩阵单元。

输出

对于每组数据,输出一个字符串,Yes或者No。

样例输入 复制

5 4
##.#
##S#
#..#
#.##
#..#
5 4
##.#
##S#
#..#
..#.
#.##

样例输出 复制

Yes
No

提示

对于30%的数据,N,M<=20

对于50%的数据,N.M<=100.

对于100%的数据,N,M<=1500,每个测试点不超过10组数据.

BFS:


#include<bits/stdc++.h>
using namespace std;
const int N = 1510;
struct coord {
    int x;
    int y;
};
//路径中的某个点,如果再次被访问到,并且,不是原来的前驱时,就可以交替进行这样的操作,不断外延出去。
//走迷宫下右上左
int dx[4] = {0, 1, 0, -1};
int dy[4] = {1, 0, -1, 0};
int n, m;
int sx, sy;//出发点坐标
char g[N][N];       //地图
int book[N][N][3];  // book[ u ][v][0]:是否访问过,book[ u ][v][1]:x,book[ u ][v][2]:y
/**
 * 功能:正数+负数取模
 */
int MOD(int a, int b) {
    return (a % b + b) % b;
}
//广度优先搜索
bool bfs() {
    queue<coord> q;           //声明队列
    q.push({sx, sy});       //将出发点放入队列
    //标识起点已使用,并且第一次到达时,真实坐标是x,y
    book[sx][sy][0] = 1, book[sx][sy][1] = sx, book[sx][sy][2] = sy;
    //开始套路
    while (!q.empty()) {
        int x = q.front().x;
        int y = q.front().y;
        q.pop();
        for (int i = 0; i < 4; ++i) {
            int tx = x + dx[i];
            int ty = y + dy[i];
            //因为可能出现负数,使用负数取模运算
            int u = MOD(tx, n), v = MOD(ty, m);
            //如果不是墙
            if (g[ u ][v] != '#') {
                //如果走过.而且与上次过来的位置不一样的话,就是肯定能走出去
                if (!book[ u ][v][0]) {
                    //没有走过,入队列
                    q.push({tx, ty});
                    //标识已使用,并且第一次到达的坐标是a,b
                    book[ u ][v][0] = 1, book[ u ][v][1] = tx, book[ u ][v][2] = ty;
                } else if ((book[ u ][ v ][1] != tx || book[ u ][v][2] != ty)) return true;
            }
        }
    }
    return false;
}
int main() {
    while (cin >> n >> m) {
        //每次清空,地图数组不用每次清空,因为每次都全新读入,自
        memset(book, 0, sizeof book);
        //双重循环读入地图
        // 注意i是从0开始,到n-1结束,这是因为:表示迷宫里(0,0)到(n-1,m-1)这个矩阵单元。
        // 注意j是从0开始,到m-1结束,这是因为:表示迷宫里(0,0)到(n-1,m-1)这个矩阵单元。
        for (int i = 0; i < n; ++i)
            for (int j = 0; j < m; ++j) {
                cin >> g[i][j];
                if (g[i][j] == 'S')sx = i, sy = j;     //标识起点
            }
        //广度优先
        if (bfs())cout << "Yes" << endl;    //可以走出幻象迷宫
        else cout << "No" << endl;            //不能走出幻象迷宫
    }
}