C++ 广度优先解决走迷宫问题

 

目录

走迷宫

解析

bfs写法


走迷宫

给定一个 n×m 的二维整数数组,用来表示一个迷宫,数组中只包含 0 或 1,其中 0 表示可以走的路,1 表示不可通过的墙壁。

最初,有一个人位于左上角 (1,1) 处,已知该人每次可以向上、下、左、右任意一个方向移动一个位置。

请问,该人从左上角移动至右下角 (n,m) 处,至少需要移动多少次。

数据保证 (1,1) 处和 (n,m) 处的数字为 0,且一定至少存在一条通路。

输入格式

第一行包含两个整数 n 和 m。

接下来 n 行,每行包含 m 个整数(0 或 1),表示完整的二维数组迷宫。

输出格式

输出一个整数,表示从左上角移动至右下角的最少移动次数。

数据范围

1≤n,m≤100

输入样例:

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

输出样例:

8

解析

如果使用dfs来做的话那么可以找出一条路径,但却不是最短的。因此我们用bfs来做这道题目,使用队列来维护其枚举的点,队列的先进先出的性质确保了只有相同层数的点被考察完了才会开始下一层的考察,这样,当第一次到达终点时,层数一定是最小的,与此同时其它的路径也考察到了这个层数,但是还没到终点。而深搜是一条道走到黑,我们无法保证它选择的那条路径是不是最短的。所以在宽搜层层扫描的情况下,最先到达终点的就是最短路径。

bfs写法

先在四周建一层围墙,防止越界,后面也无需专门去判断
使用stl

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
typedef pair<int,int> PII;
const int N=103;
int g[N][N],d[N][N]; //g存放原地图,d存放该位置是否走过并且记录做过的步数
int n,m;
int dx[]={1,0,-1,0},dy[]={0,1,0,-1};  //模拟每一个位置上下左右四个位置
queue<PII> q;
int bfs() {
    q.push({1,1}); //将第一个点放入队列
    memset(d,-1,sizeof d); // 以-1代表没有走过
    d[1][1] = 0; //0还未走动过,所以置为0
    while(!q.empty()) {
        PII t = q.front(); //取出队头元素进行操作
        q.pop();
        for(int i=0;i<4;i++) {
            int xx = t.first + dx[i], yy = t.second + dy[i]; //得到队头元素上下左右四个位置的坐标,进行判断,如果可以走并且没走过的话就加入队列,并且记录步数
            if(g[xx][yy] == 0 && d[xx][yy] == -1) {
                d[xx][yy] = d[t.first][t.second] + 1;
                q.push({xx, yy});
            }
        }
    }
    return d[n][m]; //到达终点,返回走过步数的数量
}
int main() {
    int x;
    cin >> n >> m;
    for(int i=0;i<=n+1;i++)
        for(int j=0;j<=m+1;j++) {
            //给地图四周围上墙壁,后面也就不用特判有没有越界了
            if(!i || !j || i==n+1 || j==m+1) {
                g[i][j]=1;
                continue;
            }
            scanf("%d",&x);
            g[i][j]=x;
        }

    cout << bfs() << endl;
    return 0;
}

使用自己实现的队列而不是stl的队列 

#include<iostream>
#include<cstring>
using namespace std;
typedef pair<int,int> PII;
const int N=103;
int g[N][N],d[N][N]; 
int n,m;
int dx[]={1,0,-1,0},dy[]={0,1,0,-1}; 
PII q[N*N]; //用pair<int, int> 数组模拟队列
int bfs() {
    int tt=0 ,hh=0; //tt为队列尾,hh为队列头
    q[++tt]={1,1};
    memset(d,-1,sizeof d);
    d[1][1] = 0;
    while(hh<=tt) { //表示队列中还有元素
        PII t = q[++hh]; //取出队头元素进行搜索
        for(int i=0;i<4;i++) {
            int xx = t.first + dx[i], yy = t.second + dy[i];
            if(g[xx][yy] == 0 && d[xx][yy] == -1) {
                d[xx][yy] = d[t.first][t.second] + 1;
                q[++tt] = {xx, yy};
            }
        }
    }
    return d[n][m];
}
int main() {
    int x;
    cin >> n >> m;
    for(int i=0;i<=n+1;i++)
        for(int j=0;j<=m+1;j++) {
            if(!i || !j || i==n+1 || j==m+1) {
                g[i][j]=1;
                continue;
            }
            scanf("%d",&x);
            g[i][j] = x;
        }

    cout << bfs() << endl;
    return 0;
}

打印路径版本

#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
typedef pair<int,int> PII;
const int N=103;
int g[N][N],d[N][N];
int n,m;
int dx[]={1,0,-1,0},dy[]={0,1,0,-1};
queue<PII> q;
PII Prev[N][N];
int bfs() {
    q.push({1,1});
    memset(d,-1,sizeof d);
    d[1][1] = 0;
    while(!q.empty()) {
        PII t = q.front();
        q.pop();
        for(int i=0;i<4;i++) {
            int xx = t.first + dx[i], yy = t.second + dy[i];
            if(g[xx][yy] == 0 && d[xx][yy] == -1) {
                d[xx][yy] = d[t.first][t.second] + 1;
                Prev[xx][yy]=t; //以坐标为下标将点放进数组
                q.push({xx, yy});
            }
        }
    }
    //由终点往前推,通过坐标为下标取出路径上的点
    int x=n,y=m;
    while(x || y) {
        auto t = Prev[x][y];
        cout << x << " " << y << endl;
        x = t.first, y = t.second;
    }
    return d[n][m];
}
int main() {
    int x;
    cin >> n >> m;
    for(int i=0;i<=n+1;i++)
        for(int j=0;j<=m+1;j++) {
            if(!i || !j || i==n+1 || j==m+1) {
                g[i][j]=1;
                continue;
            }
            scanf("%d",&x);
            g[i][j]=x;
        }

    cout << bfs() << endl;
    return 0;
}
  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
使用广度优先索来解决迷宫问题需要借助一个队列来实现。以下是一个基于队列的 C++ 实现示例: ```c++ #include <iostream> #include <vector> #include <queue> using namespace std; // 定义迷宫类型 typedef vector<vector<int>> Maze; // 定义状态类型 struct State { int x, y, step; }; // 定义方向数组 const int dx[] = {0, 0, 1, -1}; const int dy[] = {1, -1, 0, 0}; // 判断是否越界 bool isValid(const Maze& maze, int x, int y) { return x >= 0 && x < maze.size() && y >= 0 && y < maze[0].size() && maze[x][y] == 0; } // 广度优先索 int bfs(Maze& maze, int sx, int sy, int ex, int ey) { queue<State> q; q.push({sx, sy, 0}); // 将起点入队 maze[sx][sy] = -1; // 标记为已访问 while (!q.empty()) { State s = q.front(); q.pop(); if (s.x == ex && s.y == ey) { // 到达终点 return s.step; } for (int i = 0; i < 4; i++) { // 尝试四个方向 int nx = s.x + dx[i], ny = s.y + dy[i]; if (isValid(maze, nx, ny)) { q.push({nx, ny, s.step + 1}); // 将新状态入队 maze[nx][ny] = -1; // 标记为已访问 } } } return -1; // 无解 } int main() { // 读入迷宫 int n, m; cin >> n >> m; Maze maze(n, vector<int>(m)); for (int i = 0; i < n; i++) { for (int j = 0; j < m; j++) { cin >> maze[i][j]; } } // 索 int steps = bfs(maze, 0, 0, n - 1, m - 1); if (steps >= 0) { cout << steps << endl; } else { cout << "No" << endl; } return 0; } ``` 在上面的实现中,我们使用一个结构体来表示状态,包括当前位置坐标和已经的步数。在索过程中,我们使用一个队列来保存状态,从起点开始,依次尝试四个方向,将新状态加入队列中,直到到达终点或者队列为空为止。索过程中,我们使用 -1 表示已访问状态,0 表示未访问状态。如果找到了到终点的路径,则返回路径长度,否则返回 -1 表示无解。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zoeil

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值