P1363 幻象迷宫
题目给出多个N*M的迷宫,询问在由无限个这样的迷宫拼成的幻象迷宫中能否走到无限远
一开始认为:
起点所处的连通块必须同时接触上下或左右边相对的边缘,且边缘上接触的区域需要有交集
写出来,发现只过俩点
比如这个例子
###.#.#.#
#..S#.#.#
#.###.#.#
#.#...#.#
#.#.###.#
#.#.#...#
#.#.#.###
..#.#.#..
起点所处连通块上下边缘没有交集,但是对于拼接起来的多个迷宫可以无限走下去
发现只要在超出迷宫边缘的时候找到所对应行或列的另一边,再进行搜索就可以模拟无限走的过程
结果又不太对劲
比如这个
###.###
#######
#######
##.S..#
#...###
走到底部可以找到最顶部的一个点,同时满足连通块上下边缘都接触且接触部分有交集
所以这种情况下原来判定方法不对了
于是想到取模,在超出边缘的时候进行取模,这样可以保证下标在数组范围内
又发现如果搜索过程中 在不同的实际位置找到同一个已访问的点,那么从这个点出发之后的路已经被走过,可以无限重复,这个时候记录符合要求
否则,当起点可走的连通块走遍仍没有访问到已走过的点,那么不符合要求
没想到取模的时候负数怎么处理,结果一直卡在那,看了看题解才想起来
(发现题解想的和我一模一样,连错的思路都一样)
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
const int N = 1509;
int n, m, maze[N][N];
int sx, sy; // 起始位置
int X[N][N], Y[N][N]; // (X[x][y], Y[x][y])表示走到(x, y)点的首个实际坐标
int dx[] = {0, 1, 0, -1}, dy[] = {1, 0, -1, 0}; // 偏移量
bool vis[N][N]; // 访问标记
bool flag; // 记录是否符合要求
char a;
inline void dfs(int x, int y, int lx, int ly) {
if (flag || maze[x][y]) return; // 如果已经符合要求 或者撞到墙上
if (vis[x][y]){ // 如果已经访问
if (X[x][y] != lx || Y[x][y] != ly) flag = true;
// 从另一个不同的实际位置访问, 标记
return;
}
vis[x][y] = true, X[x][y] = lx, Y[x][y] = ly;
for (int i = 0; i < 4; i ++) { // 访问
int lxx = lx + dx[i], lyy = ly + dy[i]; // 实际坐标
int xx = (x + dx[i] + n) % n, yy = (y + dy[i] + m) % m;
// 取模后映射坐标
dfs(xx, yy, lxx, lyy);
}
}
int main() {
while (scanf("%d%d", &n, &m) != EOF) {
flag = false; // 初始化
memset(vis, 0, sizeof vis);
memset(X, 0, sizeof X);
memset(Y, 0, sizeof Y);
for (int i = 0; i < n; i ++) // 从0开始,取模运算会出现0
for (int j = 0; j < m; j ++) {
scanf(" %c", &a);
maze[i][j] = (a == '.' || a == 'S') ? 0 : 1;
if (a == 'S') sx = i, sy = j;
}
dfs(sx, sy, sx, sy);
if (flag) cout << "Yes" << endl; // 符合要求
else cout << "No" << endl; // 不符合
}
return 0;
}

浙公网安备 33010602011771号