P1363. 幻象迷宫

考点

  • DFS

题解

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
#include <bits/stdc++.h>
using namespace std;
const int LEN = 2500;
int n, m, walk[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}};
bool ans;
char arr[LEN][LEN];
struct node {
bool vis_;
int nx_, ny_;
} vis[LEN][LEN];

void dfs(int x, int y, int nx, int ny) {
if (ans) return;
x = (x + n) % n, y = (y + m) % m;
if (arr[x][y] == '#') return;
if (vis[x][y].vis_) {
if ((vis[x][y].nx_ != nx || vis[x][y].ny_ != ny)) ans = true;
return;
}
vis[x][y].vis_ = 1, vis[x][y].nx_ = nx, vis[x][y].ny_ = ny;
for (int i = 0; i < 4; ++i) {
dfs(x + walk[i][0], y + walk[i][1], nx + walk[i][0], ny + walk[i][1]);
}
}

int main() {
int x, y;
while (cin >> n >> m) {
ans = false;
memset(vis, 0, sizeof(vis));
for (int i = 0; i < n; ++i)
for (int j = 0; j < m; ++j) {
cin >> arr[i][j];
if (arr[i][j] == 'S') x = i, y = j;
}
dfs(x, y, x, y);
cout << (ans ? "Yes" : "No") << endl;
}
return 0;
}

思路

迷宫是能无限延伸的,但实际上就是个九宫格....

终止条件如下:

  • 遇到墙停止

  • 遇到之前走过的、取模后相对位置相同的起点停止,说明可以无限循环

但通过作图可以发现,不管在迷宫外还是迷宫内都有可能存在环

正常的标志数组vis只会记录坐标是否访问过,这里需要做如下改进:

  • xy为取模后的坐标,用于判断相对位置;nxny记录真实的坐标

  • nx_ny_记录上一次访问该结点的真实坐标,vis_判断该结点是否被访问过

  • 如果再次遇到某个点,其性质如下,则说明能无限循环:

    • 该点之前被访问过(vis_为真)
    • 之前访问该点的真实坐标,与当前真实坐标不同(nx != nx_ny != ny_)

    如果是环,第二次遇到该点真实坐标还是会相同;

    而若能无限循环,第二次的真实坐标肯定与第一次不同,一往无前了都