引入

我们看一个迷宫:

S**.
....
***T

(其中字符S表示起点,字符T表示终点,字符*表示墙壁,字符.表示平地。你需要从S出发走到T,每次只能向上下左右相邻的位置移动,不能走出地图,也不能穿过墙壁,每个点只能通过一次。)

我们从任意一个点都有可能往四个方向走:上、下、左或者右。我们将从S到T走路的过程称为DFS(深度优先搜索)算法。


思路

当我们搜索到了某一个点,有这样3种情况:

  1. 当前我们所在的格子就是终点。
  2. 如果不是终点,我们枚举向上、向下、向左、向右四个方向,依次去判断它旁边的四个点是否可以作为下一步合法的目标点,如果可以,那么我们就进行这一步,走到目标点,然后继续进行操作。
  3. 当然也有可能我们走到了“死胡同”里(上方、下方、左方、右方四个点都不是合法的目标点),那么我们就回退一步,然后从上一步所在的那个格子向其他未尝试的方向继续枚举。

我们将“合法的目标点”定义为:

  1. 必须在所给定的迷宫范围内、不可以是墙

我们即将访问的点不能是迷宫边界或墙,否则它是不合法的。

  1. 这个点在搜索过程中没有被走过

一个点在搜索的过程中只能被访问一次,不能重复访问。这样做是因为,如果一个点被允许多次访问,那么肯定会出现死循环的情况——在两个点之间来回走。

实现代码

#include <iostream>
using namespace std;
int n, m;
string maze[105];
int sx, sy;
bool vis[105][105];
int dir[4][2] = { { 1, 0}, {-1, 0}, {0, 1}, {0, -1}};//四个方向的方向数组
bool in(int x, int y) {
    return 0 <= x && x < n && 0 <= y && y < m;
}
bool dfs(int x, int y) {
    vis[x][y] = 1;//点已走过标记
    if (maze[x][y] == 'T') {//到达终点
        return 1;
    }
    for (int i = 0; i < 4; ++i) {
        int tx = x + dir[i][0];
        int ty = y + dir[i][1];
        if (in(tx, ty) && !vis[tx][ty] && maze[tx][ty] != '*') {
            /*
            1.in(tx, ty) : 即将要访问的点在迷宫内
            2.!vis[tx][ty] : 点没有走过
            3.maze[tx][ty] != '*' : 不是墙
            */
            if (dfs(tx, ty)) {
                return 1;
            }
        }
    }
    return 0;
}
int main() {
    cin >> n >> m;
    for (int i = 0; i < n; ++i) {
        cin >> maze[i];
    }
    for (int i = 0; i < n; ++i) {
        for (int j = 0; j < m; ++j) {
            if (maze[i][j] == 'S') {
                //记录起点的坐标
                sx = i;
                sy = j;
            }
        }
    }
    if (dfs(sx, sy)) {
        puts("Yes");
    } else {
        puts("No");
    }
    return 0;
}