走迷宫----bfs再矩阵图里的应用模版

对于之前走迷宫的那个题

回忆一下dfs的代码

#include <bits/stdc++.h>
using namespace std;
int a[110][110];
bool check[110][110];
int n,m;
int ans=1e9;
int nxt[4][2]={{1,0},{0,-1},{-1,0},{0,1}};
void dfs(int x,int y,int step){
    if(x==n&&y==m){
        ans=min(ans,step);
        return;
    }
    for(int i=0;i<4;i++){
        int nx=x+nxt[i][0];
        int ny=y+nxt[i][1];
        if(check[nx][ny]==1||nx<1||nx>n||ny<1||ny>m||check[nx][ny]==true){
            continue;
        }else{
            check[nx][ny]=true;
            dfs(nx,ny,step+1);
            check[nx][ny]=false;
        }
    }
    
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
        }
    }
    check[1][1]=true;
    dfs(1,1,0);
    cout<<ans;
}

我们是用dfs解决的,当时只是为了练习dfs的思想和熟练度,但一但地图大,方案变多,dfs就会超时。一个20*20的矩阵dfs能跑几十分钟,原因就是在dfs的回溯上,dfs算法里每个点会被遍历多次,这大大浪费了我们的时间 。

这道题的正解应该是用bfs来做,bfs时间短的原因就在于它每个点只遍历一次(还不一定遍历所有点,到目标点他就跳出循环了)。

bfs的算法我们是用队列这一数据结构实现的,为什么要用队列呢,这和这个算法的核心思想密切相关,bfs的核心就在于对当前能走到的所有点进行扩展,然后再对第一次扩展到的点找到它所能到达的所有点进行扩展,不断从起点扩展这个图直到扩展到终点。注意,在扩展完当前点能走到的所有点以后这个点就可以不要了,我们始终保留站在地图最前沿的那一批开拓者,看开拓者的位置是否为终点即可(因为一个点只要进行开拓操作,那它就一定不是终点,否则直接跳出循环就不去开拓了),不断开拓直到找到终点

这里推荐一个b站的视频模拟该过程模拟的非常好:BFS广搜解决迷宫问题_哔哩哔哩_bilibili

代码也没用到晦涩难懂的二元组之类的,很简单的结构体队列

我们结合这道题对bfs进行讲解,注释写的很明白(自认为)

#include <bits/stdc++.h>
using namespace std;
const int N=110;
int a[N][N];//存储地图数据
int n,m;//读入行数,列数
bool check[N][N];//防止往回走的check数组
struct point{/*结构体存储开拓者的坐标和这是第几次开拓到达的点(见过用二元组写的但是感觉结构体更好看懂)*/
    int x;
    int y;
    int step;
};
queue<point> aa;//定义结构体队列
int nex[4][2]={{1,0},{0,-1},{-1,0},{0,1}};//往右,下,左,上四个方向走的情况
int flag;//记录终点到达不了的情况
void bfs(){
    while(!aa.empty()){//队列非空就还能开拓,队列空了还没找到答案就是没有通往终点的路
        point t=aa.front();//取出队头元素对他进行扩展(用t承接着方便操作)
        if(t.x==n&&t.y==m){//找到终点了
            flag=1;
            cout<<t.step;
            return;
        }
        for(int i=0;i<4;i++){//分别尝试向四个方向扩展
            int nx=t.x+nex[i][0];
            int ny=t.y+nex[i][1];
            if(check[nx][ny]==true||a[nx][ny]==1||nx<1||nx>n||ny<1||ny>m){/*排除一切不符合情况的走法:走回头路,超出边界,撞到障碍物*/
                continue; 
            }else{ //满足扩展条件,入队
                point temp;//用个临时结构体承接一下要入队的数据(将数据规范整合成结构体的形式再塞入队列中)
                temp.x=nx,temp.y=ny,temp.step=t.step+1;
                aa.push(temp);
                check[nx][ny]=true;
            }
        }
        //扩展完当前队头能走的所有点后队头元素没用了(用过了),出队
        aa.pop();
    }
    if(flag==0) cout<<-1;
}
int main(){
    cin>>n>>m;
    for(int i=1;i<=n;i++){
        for(int j=1;j<=m;j++){
            cin>>a[i][j];
        }
    }
//初始化队列
    point start;
    start.x=1;start.y=1;start.step=0;
    aa.push(start);
    check[1][1]=true;
    bfs();
}

最后不得不再次感叹不同数据结构的强大 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值