走迷宫问题(BFS宽度优先搜索算法)c++

本文包含对y总代码版本的详细阐释

走迷宫

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

最初,有一个人位于左上角 (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

题解说明:

本题bfs的基本框架:设定一个队列,从图中的某一个点开始遍历,每一轮取出队头元素,通过偏移量对该点的四个方向的点进行遍历,判断其是否符合条件,直到队列为空

条件:

1.遍历到的点不超过图的边界

2.这个点应该是0(非墙壁)

3.这个点不能是已经标记走过的点 

若符合条件,那么把这个点标记为已走过,并加入队列,经过bfs操作之后,把已求出的右下角的点的距离输出来。

 

那么为什么这样遍历所得出的距离就是最短路径呢?

因为bfs是从点的四周开始一层层扩散的,每一次遍历都会搜索该点四周距离最短的点,那么一旦搜索到了目标,目标点就会被标记为已搜索过,最短距离也将定下来,那么即使后面仍然可能被搜到,也因为已标记无法改变其距离。那么我们最后得出的距离也就是最短路径了。

 

代码如下: 

#include <iostream>
#include <cstring>// 引入C字符串库,用于memset函数  
using namespace std;
const int N = 110 ;
//注意最短路问题必须要所有边的权重都为1时才能采用bfs
typedef pair<int, int > PII;// 键值对,用于表示图中的节点 ,
int n, m;// 表示图的行数和列数  
int g[N][N];    //存储图的邻接矩阵  
int d[N][N];    //存的是每一个点到起点的距离
PII q[N * N];  // 定义一个数组q,用于存储待处理的节点  

//pair类型的基本语法为pair<Type1, Type2> p,其中Type1和Type2分别表示键和值的数据类
//pair类型的对象有两个成员,分别名为first和second,可以使用普通的点操作符来访问其成员。

int bfs()   //返回从起点到终点的最短距离  
{
    int hh = 0, tt = 0; //模拟队列用于存储路径上的点
    q[0] = {0,0};     // 将起点加入队列,由于起点是左上角所以队列从(0,0)开始
    memset(d, -1, sizeof d);//先把距离初始化为-1,表示没有走过
    d[0][0] = 0; //表示已经走过了

    //用向量表示某个点的四个方向
    int dx[4] = {-1, 0, 1, 0}, dy[4] = {0, 1, 0, -1}; // 定义四个方向的偏移量  

    while(hh <= tt )//当队列不空
    {
        auto t = q[hh ++] ;     //每一次取出队头元素  auto(自动类型推断)
        for( int i = 0; i < 4; i ++ ){     // 对每一个方向进行遍历  
            int x = t.first + dx[i], y = t.second + dy[i];
            //(x,y)表示沿着这个方向走会走到哪个点
            if(x >= 0 && x < n && y >= 0 && y < m && g[x][y] == 0 && d[x][y] == -1)
            {      
                // 如果沿着这个方向走没有超过边界且该位置没有被访问过 

                d[x][y] = d[t.first][t.second] + 1;    // 更新该点的最短距离  
                q[ ++ tt] = {x,y};    // 将该点加入队列中等待处理  
            }
            
        }
    }
    return d[n-1][m-1]; //把右下角的点的距离输出来
}

int main()
{
    cin >> n >> m;
    for( int i = 0; i < n; i ++ )
    {
        for( int j = 0; j < m; j ++)
        {
            cin >> g[i][j];
        }
    }
    cout << bfs() << endl;
    
    return 0;
}

 

 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值