引入
我们看一个迷宫:
S**.
....
***T
(其中字符S表示起点,字符T表示终点,字符*表示墙壁,字符.表示平地。你需要从S出发走到T,每次只能向上下左右相邻的位置移动,不能走出地图,也不能穿过墙壁,每个点只能通过一次。)
我们从任意一个点都有可能往四个方向走:上、下、左或者右。我们将从S到T走路的过程称为DFS(深度优先搜索)算法。
思路
当我们搜索到了某一个点,有这样3种情况:
- 当前我们所在的格子就是终点。
- 如果不是终点,我们枚举向上、向下、向左、向右四个方向,依次去判断它旁边的四个点是否可以作为下一步合法的目标点,如果可以,那么我们就进行这一步,走到目标点,然后继续进行操作。
- 当然也有可能我们走到了“死胡同”里(上方、下方、左方、右方四个点都不是合法的目标点),那么我们就回退一步,然后从上一步所在的那个格子向其他未尝试的方向继续枚举。
我们将“合法的目标点”定义为:
- 必须在所给定的迷宫范围内、不可以是墙
我们即将访问的点不能是迷宫边界或墙,否则它是不合法的。
- 这个点在搜索过程中没有被走过
一个点在搜索的过程中只能被访问一次,不能重复访问。这样做是因为,如果一个点被允许多次访问,那么肯定会出现死循环的情况——在两个点之间来回走。
实现代码
#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;
}