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;
}

posted @ 2023-07-31 19:04  gHoTi  阅读(88)  评论(0)    收藏  举报