广度优先搜索BFS——迷宫解救2

1.问题分析

 在上一篇博客中A同学前往迷宫解救B同学的行动中,我们用了深度优先搜索方法,这里介绍另外一种可以使用的方法——广度优先搜索(Breadth First Search,BFS),也称为宽度优先搜索。

依旧是用一个为数组存储这个迷宫。最开始的时候A同学在迷宫(1,1)处,他可以往右走或者往下走。上一篇博客使用DFS方法我们是先让A同学先向右走,然后一直尝试下去,知道走不通的时候回到原点。

现在介绍另一种方法——通过“一层一层”扩展的方法来找大B同学。扩展时每发现一个点就将这个点加入到队列中,直至走到B同学的位置为止。

2.算法设计 

 (1):最开始A同学在(1,1)处,可以到达的坐标有(1,2)和(2,1)。

此时并没有找到B同学,所以继续往下走,假设可以走到(1,2)点,下一个点可以走到(2,2),假设走到(2,1)点,下一个点可以走到(2,2)和(3,1)。此时两个点都可以到达(2,2),为了防止一个点多次被走到,我们需要一个数组来记录书否这个点已经被走到过。

现在我们到达了(2,2)或者(3,1),也并没有找到B同学的为止,所以我们要重复上述的方法。假设现在我们到达(2,2),我们可以往下到达(2,3)和(3,2);假设我们现在到达(3,1),我们可以往下到达(3,2)和(4,1)。

(2):回顾上面的过程,我们确定数据结构:我们可以用一个队列来模拟上述的过程,这里我们还是用一个结构体还实现队列(C++也可以直接用STL的队列头文件)

扫描二维码关注公众号,回复: 9102731 查看本文章
struct note
{
    int x;//横坐标
    int y;//纵坐标
    int step;//步数
};
struct note que[N];//队列
int head;
int tail;
int maze[N][N]={0};//初始化地图
int marked[N][N]={0};//标记数组,判断是否被访问
head=1;
tail=1;
//指向队列头
//第一步将(1,1)加入队列,因为此处是起点,默认已经在队列中
que[tail].x=1;
que[tail].y=1;
que[tail].step=0;
tail++;//往下走
marked[1][1]=1;//此时(1,1)已经访问过。

(3):从(1,1)开始,到达(1,2)。

tx=que[head].x;
ty=que[head].y+1;

(4):我们需要判断(1,2)是否越界。

if(tx<1 || tx>n || ty<1 || ty>m)
{
    continue;
}

(5):再判断(1,2)是否为障碍物或者已经在路径中。

if(maze[tx][ty]==0 && marked[tx][ty]==0)
{
    
}

(6):如果满足上述条件,就将(1,2)放入队列。

marked[tx][ty]=1;
que[tail].x=tx;
que[tail].y=ty;
que[tail].step=que[head].step+1;
tail++;

(7):接下来还要继续往别的方向走。我们规定一个顺序:右,下,左,上。当(1,1)扩展完成后,(1,1)现在对我们来说已经没有用了,我们就将(1,1)出列。出列之后,现在队列的head正好指向(1,2)这个点,通过这个点我们继续扩展,最后将(2,2)也加入队列。(1,2)操作完毕,也将(1,2)出列。以此类推,接下来都是这样的操作。

(8):为了方便扩展,我们还需要一个方向函数:

int next[4][3]={{0,1},{1,0},{0,-1},{-1,0}};

3.源代码 

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=111;

struct note
{
    int x;//横坐标
    int y;//纵坐标
    int step;//步数
};

int next[4][3]= {{0,1},{1,0},{0,-1},{-1,0}};

int main()
{
    struct note que[N*N];//队列
    int head;
    int tail;
    int maze[N][N]= {0}; //初始化地图
    int marked[N][N]= {0}; //标记数组,判断是否被访问
    int next[4][3]= {{0,1},{1,0},{0,-1},{-1,0}};//方向数组。
    int n;
    int m;
    int startx;
    int starty;
    int p;
    int q;
    int tx;
    int ty;
    int flag;
    cout << "请输入迷宫的行数n和列数m" << endl;
    cin >> n>> m;
    cout << "请输入迷宫maze" << endl;
    for(int i=1; i<=n; i++)
    {
        for(int j=1; j<=m; j++)
        {
            cin >> maze[i][j];
        }
    }
    cout << "请输入起点的坐标和目标的坐标:"<< endl;
    cin >> startx >> starty >> p >> q;
    head=1;
    tail=1;
    //指向队列头
    //往队列插入迷宫入口坐标:
    //第一步将(1,1)加入队列,因为此处是起点,默认已经在队列中
    que[tail].x=1;
    que[tail].y=1;
    que[tail].step=0;
    tail++;//往下走
    marked[1][1]=1;//此时(1,1)已经访问过。
    flag=0;//用来标记是否已经到达目标点。

    while(head<tail)
    {
        //枚举四个方向
        for(int k=0; k<=3; k++)
        {
            tx=que[head].x+next[k][0];
            ty=que[head].y+next[k][1];
            //判断是否越界:
            if(tx<1 || tx>n || ty<1 || ty>m)
            {
                continue;
            }
            //判断是否是障碍物和是否已经访问:
            if(maze[tx][ty]==0 && marked[tx][ty]==0)
            {
                marked[tx][ty]=1; //此时已经访问过
                que[tail].x=tx;
                que[tail].y=ty;
                que[tail].step=que[head].step+1;
                tail++;
            }
            if(tx==p && ty==q)
            {
                flag=1;
                break;
            }
        }
        if(flag==1)
        {
            break;
        }
        head++;//将已经扩展过的点出列。
    }
    cout << "A同学找到B同学的最短距离是:"<< que[tail-1].step << endl;
    return 0;
}

4.测试结果 

 

发布了57 篇原创文章 · 获赞 9 · 访问量 3623

猜你喜欢

转载自blog.csdn.net/Jayphone17/article/details/102717815