问小白 wenxiaobai
资讯
历史
科技
环境与自然
成长
游戏
财经
文学与艺术
美食
健康
家居
文化
情感
汽车
三农
军事
旅行
运动
教育
生活
星座命理

迷宫游戏的DFS算法解析与C++实现

创作时间:
作者:
@小白创作中心

迷宫游戏的DFS算法解析与C++实现

引用
CSDN
1.
https://blog.csdn.net/yymer214/article/details/138919926

我们来玩一个迷宫游戏,尝试走一下面的迷宫。

迷宫游戏

我们用一个二维的字符数组来表示前面画出的迷宫:

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

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

很明显,当我们从任意格子出发,都有可能往四个方向走:上,下,左,右。而初始的时候,我们是在起点S处,之后开始进行我们的搜索过程,也就是我们要讲的 DFS 算法。

那么当我们搜索到了某一个格子(也就是我们下一步会从该格子出发的时候):

  1. 首先要判断一下当前格子是否就是终点,如果是,那么就表示我们已经成功的从起点S移动了若干步之后到达了终点T,便成功地完成了这个问题。

  2. 否则我们就需要从该格子出发,可以分别枚举向左、向下、向右、向上四个方向,依次去判断它旁边的四个点是否可以作为下一步合法的目标点,如果可以,那么我们就进行这一步,走到目标点,然后继续进行操作。

  3. 当然有可能左、下、右、上四个点都无法再成为合法的目标点了,那么我们就回退一步,然后从上一步所在的那个格子向其他 未尝试的方向 继续枚举。

关于合法的定义如下:

  • 必须在所给定的迷宫范围内。 如样例中是一个 4 行 3 列的迷宫,那么这个点必须在 (0,0)−(3,2) 的范围中才能称为合法,否则即为不合法。

  • 这个点在搜索过程中必须没有被访问过。 也就是说,一个点在 DFS 的过程中只能被访问一次,不能重复访问。这样做是因为,如果一个点允许多次访问,那么肯定会出现死循环的情况——在两个点中间来回走。不过,根据题意,在某些情况下,你回溯了之后可以视回溯前的点为没有访问过。

  • 这个点必须不是墙壁。这个显然很好理解,我们只能走在平地上,不能走在墙壁上也不能穿过墙壁。

DFS 走迷宫对应的伪代码框架如下:

// 对坐标为 (x, y) 的点进行搜索
bool dfs(int x, int y) {
    if (x, y) 是终点 {
        // 找到了路径
        return true;
    }
    // 标记 (x, y) 已经访问
    // 向上走到位置 (tx, ty)
    if (tx, ty) 合法 {
        if (dfs(tx, ty) == true) {
            // 递归调用 DFS 函数,将(tx, ty)作为当前状态进行搜索,下同。
            return true;
        }
    }
    // 向左走到位置 (tx, ty)
    if (tx, ty) /* 合法 */ {
        if (dfs(tx, ty) == true) {
            return true;
        }
    }
    // 向下走到位置 (tx, ty)
    if (tx, ty) /* 合法 */ {
        if (dfs(tx, ty) == true) {
            return true;
        }
    }
    // 向右走到位置 (tx, ty)
    if (tx, ty) /* 合法 */ {
        if (dfs(tx, ty) == true) {
            return true;
        }
    }
    return false;
}  

迷宫搜索2(输出路径):

#include <iostream>
#include <string>
using namespace std;
int n, m;
string maze[110];
int sx, sy;
bool vis[110][110];
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] = true;
    if (maze[x][y] == 'T') {
        return true;
    }
    maze[x][y] = 'm';
    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] != '*') {
            if (dfs(tx, ty)) {
                return true;
            }
        }
    }
    maze[x][y] = '.';
    return false;
}
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)) {
        cout << "Yes" << endl;
    } else {
        cout << "No" << endl;
    }
    for(int i = 0; i < n; i++){
        cout << maze[i] << endl;
    }
    return 0;
}  
© 2023 北京元石科技有限公司 ◎ 京公网安备 11010802042949号