迷宫问题(DFS方法)

文章介绍了一个使用深度优先搜索(DFS)算法解决从迷宫左上角到右下角的最短路径问题。给定一个5x5的二维数组表示迷宫,1代表墙壁,0代表可行走路径。DFS函数通过递归地检查所有可能的下一步来寻找路径,同时避免重复访问已探索过的点。当找到出口时,程序返回路径并打印出路径上的坐标。

Description

定义一个二维数组:

int maze[5][5] = {
	0, 1, 0, 0, 0,
	0, 1, 0, 1, 0,
	0, 0, 0, 0, 0,
	0, 1, 1, 1, 0,
	0, 0, 0, 1, 0,
};
它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。

Input

一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。

Output

左上角到右下角的最短路径,格式如样例所示。

Sample Input

0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0
Sample Output
(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)

用深度优先搜索来实现这个方法,dfs函数的功能是解决当前应该怎么办,所以我们每走到一个点都需要进行处理:

①判断我们有没有走到迷宫的终点,如果没有到达就找出下一步可以走的地方。所以dfs函数只需要维护2个参数,分别是当前这个点的 x 坐标和y 坐标

void DFS(int x, int y)
{
    
    //判断是否找到了迷宫的出口
    if (x == 4 && y == 4)
    {
        flag = 1;
        return;//返回上一层dfs函数
    }

②如果没有到达迷宫的终点, 则找出下一步可以走的地方,因为有四个方向可以走,为了操作方便,我定义了一个方向数组

    int next[4][2] = { {0,1},{1,0},{0,-1},{-1,0} };//向右,向下,向左,向上

通过这个方向数组,使用循环就很容易获得下一步的坐标。 这里将下一步的横坐标用 tx存储, 纵坐标用 ty 存储。如果循环结束,发现无路可走,就会回退一步,即返回上一层dfs函数

 for (int k = 0; k < 4; k++)
    {
        //计算下一个点的坐标
        tx = x +next[k][0];
        ty = y + next[k][1];

③接下来我们就要对下一个点(tx,ty)进行一些判断。 包括是否越界,是否为障碍物,以及这个点是否已经在路径中 (即避免重复访问一个点,需要用 book[tx][ty]来记录格子(tx,ty)是否已经在路径中
如果这个点符合所有的要求, 就对这个点进行下一步的扩展,即dfs(tx,ty)

 for (int k = 0; k < 4; k++)
    {
        //计算下一个点的坐标
        tx = x +next[k][0];
        ty = y + next[k][1];
        //不能越界
        if (tx < 0 || ty < 0 || tx >= 5 || ty >= 5)
            continue;
        //判断该点是否为障碍物或者已经在路径中
        if (maze[tx][ty] == 0 && book[tx][ty] == 0)
        {
            book[tx][ty] =1;
            DFS(tx, ty);//开始尝试这一个点
            //可以走到终点,则返回
            if (flag)
                return;
        }
    }
    //循环结束后,发现尝试失败,则取消这个点的标记,并回退到上一层dfs函数
    book[tx][ty] = 0;
    step--;
    return;

完整代码:

#include<iostream>
using namespace std;
int maze[10][10];
int pos[10][10];
int book[10][10];
int step,flag;

void DFS(int x, int y)
{
    //记录到达位置的下标
    pos[step][0] = x; pos[step][1] = y;
    step++;
    //标记这个点已经走过
    book[x][y] = 1;
    //判断是否找到了迷宫的出口
    if (x == 4 && y == 4)
    {
        flag = 1;
        return;//返回上一层dfs函数
    }
    int next[4][2] = { {0,1},{1,0},{0,-1},{-1,0} };//向右,向下,向左,向上
    int tx, ty, k;
    //枚举四种走法
    for (int k = 0; k < 4; k++)
    {
        //计算下一个点的坐标
        tx = x +next[k][0];
        ty = y + next[k][1];
        //不能越界
        if (tx < 0 || ty < 0 || tx >= 5 || ty >= 5)
            continue;
        //判断该点是否为障碍物或者已经在路径中
        if (maze[tx][ty] == 0 && book[tx][ty] == 0)
        {
            book[tx][ty] =1;
            DFS(tx, ty);//开始尝试这一个点
            //可以走到终点,则返回
            if (flag)
                return;
        }
    }
    //尝试失败,取消这个点的标记
    book[tx][ty] = 0;
    step--;
    return;
}
int main()
{
    for (int i = 0; i < 5; i++)
    {
        for (int j = 0; j < 5; j++)
            cin >> maze[i][j];
    }
    DFS(0, 0);
    for (int i = 0; i < step; i++)
        cout << "(" << pos[i][0] << ", " << pos[i][1] << ")" << endl;
    return 0;
}


 


 


 

### 迷宫问题中的DFS和BFS算法 #### DFS深度优先搜索) 在迷宫求解中,DFS采用的是深入探索的方式直到无法继续前进为止再回溯其他可能路径的方法。该方法利用栈结构来记录访问过的节点以及当前所处位置,在遇到死胡同时会返回上一步并尝试新的方向[^1]。 对于迷宫问题而言,当仅需找到一条从起点到终点的有效路径而不在乎是否为最短路径时,DFS是一个不错的选择;然而其缺点在于可能会遍历较多不必要的分支从而浪费时间资源[^2]。 ```cpp void dfs(int x, int y){ if (maze[x][y] == END){ // 到达出口 success = true; return ; } visited[x][y] = true; // 标记已走过 for (int i=0;i<4;++i){ // 尝试四个方向移动 int nx=x+dx[i], ny=y+dy[i]; if (!success && isValid(nx,ny)){ path.push_back({nx,ny}); dfs(nx,ny); if(!success) path.pop_back(); // 回溯 } } } ``` #### BFS(广度优先搜索) 相比之下,BFS则更倾向于一层层向外扩展邻居结点直至触及目标点位停止。此过程借助队列完成,每次都将新发现却未曾踏足之处加入待处理列表之中等待后续考察。由于这种特性决定了它总能最先抵达离起始最近的目的地因此特别适合用来寻找两点间最短距离的问题场景下使用[^3]。 ```cpp bool bfs(){ queue<pair<int,int>> q; vector<vector<bool>> seen(rows,vector<bool>(cols,false)); q.emplace(startX,startY); seen[startX][startY]=true; while(!q.empty()){ auto [cx,cy]=q.front(); q.pop(); if(maze[cx][cy]==END) return true; for(auto& d : directions){ int nx=cx+d.first , ny=cy+d.second ; if(isValid(nx,ny)&&!seen[nx][ny]){ parent[{nx,ny}]={cx,cy}; seen[nx][ny]=true; q.emplace(nx,ny); } } } return false; } ``` #### 应用对比 - **适用范围** - 如果只需要知道是否存在通路而不关心具体长度,则可以考虑效率较高的DFS。 - 若要获取确切的最短路线方案,则应选用能够保证首次到达即最优解特性的BFS。 - **性能考量** - 对于较小规模的地图数据集来说两者差异不大; - 随着地图尺寸增大,考虑到内存占用等因素影响,通常认为BFS所需额外存储空间较大因为它要保存每一层所有未被探测过的位置信息以便下一步操作,所以实际运行速度未必优于DFS。 - **实现难度** - 实现方面二者都较为简单直观易于理解掌握,但在编码细节上有一定差别比如循环终止条件判断、边界情况处理等都需要仔细斟酌确保逻辑严谨无误。
评论 1
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值