精华内容
下载资源
问答
  • 宽度优先搜索——走迷宫
    2022-02-21 22:09:43

    给定一个 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

     Code:

    #include <iostream>
    #include <stdio.h>
    #include <cstring>
    
    using namespace std;
    
    typedef pair<int, int> PII;
    
    const int N = 110;
    
    int g[N][N], d[N][N];
    int n, m;
    PII q[N * N];//这里的q可以换成队列
    
    int bfs()
    {
        memset(d, -1, sizeof d);
        d[0][0] = 0;
        q[0] = {0, 0};
        const int dx[4] = {0, 1, 0, -1}, dy[4] = {1, 0, -1, 0};
        int hh = 0, tt = 0;
        while(hh <= tt)
        {
            auto t = q[hh ++ ];
            for(int i = 0; i < 4; i ++ )
            {
                int x = t.first + dx[i], y = t.second + dy[i];
                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];
    }
    
    signed main()
    {
       scanf("%d%d", &n, &m);
       for(int i = 0; i < n; i ++ )
       {
           for(int j = 0; j < m; j ++ )  scanf("%d", &g[i][j]);
       }
       cout << bfs() << endl;
    }

    更多相关内容
  • 主要为大家详细介绍了Python深度优先算法生成迷宫,具有一定的参考价值,感兴趣的小伙伴们可以参考一下
  • 例8.4迷宫问题 如图所示,给出一个n*m的迷宫图和一个入口、一个出口 编写一个程序,打印从一条从迷宫入口到出口的路径。这里黑色方块的单元表示走不通(用-1表示),白色表示可以走(用0表示) 只能往上、下、左、右...
  • 实现的功能是:随机生成迷宫地图和入口,出口位置,然后利用这两种搜索算法自动走出迷宫。用到的工具是C++的MFC,可以看到运动轨迹。 第一次做C++项目,代码优点乱。可以直接运行My_QQ.sln文件。
  • 算法流程(基于宽度优先) 3.1 步骤流程: 一、 从初始节点 S 出发,将初始节点加入队列 Q,此时 Q={(0,0)},已搜索节 点表 C={ }; 二、 若队列 Q 为空,则搜索失败,退出; 三、 若队列 Q 不为空,则取出队列 Q 的头...

    正文之前

    国庆最后一天,也是准备爆肝五年这个历史性任务开启的前一天,今天很伤,但是么~

    514052973cd5?utm_source=oschina-app

    蝼蚁聚团求存,强者则与寂寞和星空为伴

    哈哈,这句话居然还是我超喜欢的小说之一的作者写的。。。果然,英雄所见略同:

    514052973cd5?utm_source=oschina-app

    所以,请计算机2018级《人工智能》课堂的兄弟,看到这里就自觉关闭网页吧。。。。我写了一下午。。。想留着纪念下。。不想明天直接就是一大片一样的。。

    正文

    作业需求如下,其实很简单啦!~

    514052973cd5?utm_source=oschina-app

    需求分析

    起点状态其实就对应初始状态,起点可走周围四个方向(过程中需对是否越界,是 否撞墙做出判断,不满足条件都为不可到达的状态,生成子节点时可直接不考虑), 一旦遍历的点为终点这时经历的路径必为最短,即经历的层数最少,当然,此路径并 不唯一,取最先达到终点的路径为优先。

    算法流程(基于宽度优先)

    3.1 步骤流程:

    一、 从初始节点 S 出发,将初始节点加入队列 Q,此时 Q={(0,0)},已搜索节 点表 C={ };

    二、 若队列 Q 为空,则搜索失败,退出;

    三、 若队列 Q 不为空,则取出队列 Q 的头结点,检查 C 中是否有该节点; 四、 若有该节点,则退出此线路;

    五、 若无该节点,则将该节点置入 C 中,再判断该节点是否为目标节点;

    六、 若为目标节点,则由该节点回溯到初始节点,即可得到路径,后退出搜索; 七、 若不是目标节点,那么将该节点扩展,得到其扩展子节点,先过滤掉已经在 C

    中存在的子节点,然后设置所有子节点的父节点为当前节点,并且将所有子节

    点入队; 八、 回到步骤二.

    3.2 关键点分析

    上述步骤中,初始化动作为步骤一,步骤二到步骤八是循环操作。其中有三处跳出 循环的点:

    队列 Q 为空时,代表着所有的节点能从初始点到达的节点都已经搜索完毕,可以 直接结束程序(break);

    如果当前节点是搜索过的节点,那么退出本次循环,进入下次循环(continue); 3. 找到了目标节点,回溯至初始节点后得到路径,完美退出(exit)。

    代码放一放:

    514052973cd5?utm_source=oschina-app

    输出结果如图:

    514052973cd5?utm_source=oschina-app

    正文之后

    我知道这个算法实现写的稀烂的。。。而且讲道理,我觉得很是有点广度优先的意思在里头了。。。这。。很可怕了~ 不过不管了。写了那么久,将就着用吧!溜了,吃饭去了

    展开全文
  • 迷宫生成算法---深度优先算法总体的目录版权及协议声明1. 深度优先算法的原理与思路二.迷宫的制作迷宫的总体的创建。三.代码的实现 总体的目录 版权及协议声明 本文章遵循CC BY-NC 4.0协议,即允许共享,不允许商用,...

    总体的目录

    版权及协议声明

    本文章遵循CC BY-NC-SA 4.0协议,即知识共享-署名-非商业性使用-相同方式共享

    更加舒服的阅读方式

    该文章的pdf版,排版更舒服(其实是因为不会csdn的排版)
    链接:https://pan.baidu.com/s/1vl4D__WK-YDyDVWydqdj5Q
    提取码:2233

    完成后的代码
    链接:https://pan.baidu.com/s/1BanSKbRiWTytvByct0fErw
    提取码:2233

    一. 深度优先算法的原理与思路

    首先来看一下算法导论上的解释:

    深度优先搜索总是对最近才发现的结点v的出发边进行探索,直到该结点的所有出发边都被发现为止。一但结点v的所有出发边都被发现,搜索则“回溯”到v的前驱结点(v是经过该结点才被发现的),来搜索该前驱结点的出发边。该过程一直持续到从源结点可以达到的所有结点都被发现为止。如果还存在尚未发现的结点,则深度优先搜索将从这些未被发现的结点中任选一个作为新的源点,并重复同样的搜索过程。该算法重复整个过程,直到图中的所有结点都被发现为止。

    用人话的方式来说明:

    1. 选一个起点
    2. 查看周围能够移动的点并随即挑一个移动
    3. 重复步骤2直到周围没有可以移动的点
    4. 回溯一格,即回到到当前位置的上一个位置,并执行步骤2和3

    二.迷宫的制作

    知道了这个算法的原理以后就可以开始准备制作迷宫的模型了。
    迷宫分为两个部分,一个是路,一个是墙。那么就有两种制作出来的形态:第一种是墙是一条线,路是一个方格。

    第一种
    第二种是墙和路都是方格,墙是实心的路是空心的

    在这里插入图片描述
    两个方式表现出来的特点是显而易见的,第一种的容量在地图的大小相同的情况下是比第二种的容量大的
    那么这个代码中创建出来的迷宫则是第二种形态。

    在这里插入图片描述

    迷宫的总体的创建。

    首先我们要设定这个迷宫的长和宽。由于我们要保证地图中不会生成2*2的正方形块,以及要保证地图里的每一个陆块都能相互连接,所以我们要让长和宽都为2n+1(n∈Z+)(换一个说法:如果有n条路,那么就一定有n+1个墙,所以就为2n+1个格子)
    那么这个地图的框架就出来了:在这里插入图片描述
    接下来就是生成路径
    首先我们规定:

    黄色的方块为当前的位置
    绿色为上一个方块的位置
    蓝色为黄色的方块可以走的位置
    粉色为生成的路径

    那么就以左上角的方块为起点:
    在这里插入图片描述
    它可以向两个方向走,即:
    在这里插入图片描述
    之后随机挑选一个,以下面的方块为例:
    在这里插入图片描述
    接下来选择右边的方块:
    在这里插入图片描述
    以此类推…
    这就是路径生成的过程

    那么我们接下来看我们步骤4所反应的情况:
    在这里插入图片描述
    当遇到这个情况时,就回溯到上一个方格所在的位置,即绿色方格的位置:
    在这里插入图片描述
    那么我们可以看到,回溯一次的时候就有了新的路径,接下来就是继续移动格子,继续创建地图.
    当地图中所有的格子均检测过的时候,我们的黄色格子就会回到了左上角在这里插入图片描述
    因此,我们可以检测黄色格子的位置来判断地图是否生成完毕.

    三.代码的实现

    首先,先附上完整的代码:

    import random
    import sys
    sys.setrecursionlimit(5000)
    width_set =int(input("请输入宽度"))
    height_set = int(input("请输入高度"))
    
    if width_set<4 or height_set<4:
        width_set=11
        height_set=11
        print("输入的尺寸过小,已自动调节成,宽度:11,高度:11")
    if width_set%2 !=1:
        width_set +=1
        print("宽度请输入奇数,已自动矫正为:"+str(width_set))
    if height_set%2 !=1:
        height_set +=1
        print("高度请输入奇数,已自动矫正为:"+str(height_set))
    
    map = [[0 for width in range(width_set)] for height in range(height_set)]
    
    class cube:
        loc_x=0#当前的x坐标
        loc_y=0#当前的y坐标
        from_x = 0#上一个格子的x坐标
        from_y = 0#上一个格子的y坐标
        Iswall = True#是否是墙
    
    for height in range(0,height_set):
        for width in range(width_set):
            map[height][width] = cube()
            map[height][width].loc_y = height
            map[height][width].loc_x = width
    
    def spawn(local_map=[]):
        Waypoints_ing =[]#当函数运行时用来添加备选路点
        width = local_map.loc_x
        height = local_map.loc_y
    
        map[height][width].Iswall = False
        if width>2:#判断左边的格子
            if map[height][width-2].Iswall == True:
                Waypoints_ing.append(map[height][width-2])
                map[height][width-2].from_x = width
                map[height][width-2].from_y = height
    
        if height>2:#判断上边的格子
            if map[height-2][width].Iswall == True:
                Waypoints_ing.append(map[height-2][width])
                map[height-2][width].from_x = width
                map[height-2][width].from_y = height
    
        if width<width_set-2:#判断下边的格子
            if map[height][width+2].Iswall == True:
                Waypoints_ing.append(map[height][width+2])
                map[height][width+2].from_x = width
                map[height][width+2].from_y = height
    
        if height<height_set-2:#判断上边的格子
            if map[height+2][width].Iswall == True:
                Waypoints_ing.append(map[height+2][width])
                map[height+2][width].from_x = width
                map[height+2][width].from_y = height
    
        if(local_map.from_x !=0 and local_map.from_y!=0):
            map[int((local_map.from_y+height)/2)][int((local_map.from_x+width)/2)].Iswall = False
        if(len(Waypoints_ing)>0):#如果有元素
            targetnum = random.randint(0,len(Waypoints_ing)-1)#生成一个关于Waypoints_ing的随机的下标
            spawn(Waypoints_ing[targetnum])#进行下一次的递归
        else:
            if map[height][width].from_y ==1 and map[height][width].from_x==0:#如果回溯的目标为初始点的时候
                return#从递归中跳出
            spawn(map[map[height][width].from_y][map[height][width].from_x])#如果不是初始点,那么就在回溯目标的格子上继续递归
    
    def printmap():
        out=""
        for height in range(height_set):
            for width in range(width_set):
                if map[height][width].Iswall ==True:
                    out = out+"■ "
                else:
                    out = out +"  "
                    
                if width == width_set-1:
                    out = out +"\n"
        print(out)
    map[1][0].Iswall = False
    map[1][1].from_x = 0
    map[1][1].from_y = 1
    spawn(map[1][1])#从坐标为(1,1)的格子开始做递归
    printmap()
    
    

    那么接下来我们来一步一步的完成这个代码的构建

    首先,我们要能创建指定长宽的矩形点阵:
    那么就需要检测用户的输入:

    width_set =int(input("请输入宽度"))
    height_set = int(input("请输入高度"))
    

    width_set就是我们设置的宽度
    height_set则是我们设置的高度
    接下来就是要一个矩形的点阵,那么我们就能想到,可以通过二维列表来建立相应的结构

    map = [[0 for width in range(width_set)] for height in range(height_set)]
    

    先创建总行数,再创建总列数,所以要选择里面的元素的时候要先写这个元素所在的行数再输入所在的列数
    那么这个地图里的任意一点(x,y)都可以表示为map[y][x]
    至于为什么要用生成器而不是直接用*的方式来创建可以参考这个文章https://zhuanlan.zhihu.com/p/88197389

    接下来我们要让二维列表中的每一个元素都有相对于自身的属性(比如当前的位置,是不是墙,有没有检测过等)
    所以我们需要创建一个关于方格的类来存放这些东西

    class cube:
        loc_x=0#当前的x坐标
        loc_y=0#当前的y坐标
        from_x = 0#上一个格子的x坐标
        from_y = 0#上一个格子的y坐标
        Iswall = True#是否是墙
    
    

    当然,从总代码中可以看到不是只有这些属性,其他的属性会在接下来需要的时候添加上去.
    那么已经设置好了格子的属性以后就要让二维列表中的元素成为这个类的对象.
    用两个for循环来实现所有元素的实例化并且记录当前的位置

    for height in range(0,height_set):
            for width in range(width_set):
                map[height][width] = cube()
                map[height][width].loc_y = height
                map[height][width].loc_x = width
    
    

    那么我们可以来看一下目前为止的成果了.我们现在来输出已经创建好的地图:

    def printmap():
        out=""
        for height in range(height_set): #遍历行
            for width in range(width_set): #遍历列
                if map[height][width].Iswall ==True:
                    out = out+"■ "
                else:
                    out = out +"  "
                if width == width_set-1:
                    out = out +"\n"
        print(out)
    
    

    由代码可以看到,我把这个过程进行了一个封装,将它变成了一个方法
    这个代码的原理是,先设立一个空的字符串out,接下来一行一行的判断应该输出的究竟是墙还是路,如果是路那么就在字符串的结尾加上两个空格,如果是墙就加上一个方块和一个空格,如果要换行了,就加上\n(在print的时候会换行).

    那么之后要用这个方法的时候只需要调用一下就可以了.

    接下来我们就要开始写整个代码中最重要的部分,即迷宫生成的部分.

    首先先将height指定为当前的y值,将width指向当前的x值

    width = local_map.loc_x
    height = local_map.loc_y
    
    

    在这里插入图片描述
    我们以这个图为例,当前的width_set为7,height_set也为7
    那么我们现在选中的格子的坐标是(1,1)
    那么我们要向这个方块的四周进行检测首先我们先向下面进行检测.那么这个手就会有一个问题:什么时候应该停止
    通过上面的图就可以发现当当前的y轴坐标大于等于height_set-2的时候就应该停止,或者说:当当前的y轴坐标小于height_set-2的时候就可以检测.
    那么为什么一定要是这样呢?当y的坐标大于或等于height_set-2时,下一个目标的位置就在边界上或者是在地图以外的位置了.
    在代码中的体现:

    if height<height_set-2:
    

    现在就完成了一个方向的判断,其余的四个方向也是这样判断的

    现在已经保证了选的格子是在地图的范围以内的
    那么现在就要来判断备选的目标是否是墙:

    if map[height+2][width].Iswall == True:
    

    比如当前目标格子的下面的格子(3,1),如果是墙,那么就将这个点添加到备选的点:

    Waypoints_ing.append(map[height+2][width])
    

    并且将下面格子的回溯格子的坐标的指向当前的格子的坐标:

    map[height+2][width].from_x = width
    map[height+2][width].from_y = height
    
    

    接下来的三个方向都是相同的处理:

    if width>2:#判断左边的格子
            if map[height][width-2].Iswall == True:
                Waypoints_ing.append(map[height][width-2])
                map[height][width-2].from_x = width
                map[height][width-2].from_y = height
    
        if height>2:#判断上边的格子
            if map[height-2][width].Iswall == True:
                Waypoints_ing.append(map[height-2][width])
                map[height-2][width].from_x = width
                map[height-2][width].from_y = height
    
        if width<width_set-2:#判断下边的格子
            if map[height][width+2].Iswall == True:
                Waypoints_ing.append(map[height][width+2])
                map[height][width+2].from_x = width
                map[height][width+2].from_y = height
    
        if height<height_set-2:#判断上边的格子
            if map[height+2][width].Iswall == True:
                Waypoints_ing.append(map[height+2][width])
                map[height+2][width].from_x = width
                map[height+2][width].from_y = height
    
    

    其中Waypoints_ing的创建(要放在上面的代码的前面)

    Waypoints_ing =[]#当函数运行时用来添加备选路点
    

    当完成对四个方向的判断以后Waypoints_ing里面就包含了可以移动的目标格子
    接下来就要判断Waypoints_ing里面的元素,如果Waypoints_ing里面了元素,即当前的格子周围没有可以移动的格子,那么就回溯想一个格子,如果有可以移动的格子,那么就从中随机挑选一个,做下一次的递归.
    由于我们要用到random函数,所以需要引用random库

    import random
    if(local_map.from_x !=0 and local_map.from_y!=0):
            map[int((local_map.from_y+height)/2)][int((local_map.from_x+width)/2)].Iswall = False
        if(len(Waypoints_ing)>0):#如果有元素
            targetnum = random.randint(0,len(Waypoints_ing)-1)#生成一个关于Waypoints_ing的随机的下标
            spawn(Waypoints_ing[targetnum])#进行下一次的递归
        else:
            if map[width][height].from_y ==1 and map[height][width].from_x==0:#如果回溯的目标为初始点的时候
                return#从递归中跳出
            spawn(map[map[height][width].from_y][map[height][width].from_x])#如果不是初始点,那么就在回溯目标的格子上继续递归
    
    

    接下来,我们对以上的代码进行一个整理,将他放进一个方法里:

    def spawn(local_map=[]):
        Waypoints_ing =[]#当函数运行时用来添加备选路点
        width = local_map.loc_x
        height = local_map.loc_y
    
        ########空槽1##################
        if width>2:#判断左边的格子
            if map[height][width-2].Iswall == True:
                Waypoints_ing.append(map[height][width-2])
                map[height][width-2].from_x = width
                map[height][width-2].from_y = height
    
        if height>2:#判断上边的格子
            if map[height-2][width].Iswall == True:
                Waypoints_ing.append(map[height-2][width])
                map[height-2][width].from_x = width
                map[height-2][width].from_y = height
    
        if width<width_set-2:#判断下边的格子
            if map[height][width+2].Iswall == True:
                Waypoints_ing.append(map[height][width+2])
                map[height][width+2].from_x = width
                map[height][width+2].from_y = height
    
        if height<height_set-2:#判断上边的格子
            if map[height+2][width].Iswall == True:
                Waypoints_ing.append(map[height+2][width])
                map[height+2][width].from_x = width
                map[height+2][width].from_y = height
    ############空槽2########################
        if(len(Waypoints_ing)>0):#如果有元素
            targetnum = random.randint(0,len(Waypoints_ing)-1)#生成一个关于Waypoints_ing的随机的下标
            spawn(Waypoints_ing[targetnum])#进行下一次的递归
        else:
            if map[height][width].from_y ==1 and map[height][width].from_x==0:#如果回溯的目标为初始点的时候
                return#从递归中跳出
            spawn(map[map[height][width].from_y][map[height][width].from_x])#如果不是初始点,那么就在回溯目标的格子上继续递归
    
    

    仔细看一下是不是会发现好像少了什么东西?对的,少了路径的生成,所以我们需要在进行每一次的递归的时候先将当前位置的方块的Iswall属性设置成false,并且打通当前格子和下一个执行递归的格子之间的墙

      map[height][width].Iswall = False
    

    (放在空槽1)

        if(local_map.from_x !=0 and local_map.from_y!=0):
            map[int((local_map.from_y+height)/2)][int((local_map.from_x+width)/2)].Iswall = False
    
    

    (放在空槽2)

    现在经过这些代码的运算可以将地图内所有的点都经行判断,但是就单单这样进行运行会发现报错了,那么这个的原因就是终止的条件没有满足:
    在这里插入图片描述
    为什么呢?从代码中可以看到这个递归终止的条件是当前的回溯的目标坐标为(1,0)时结束递归,也就是说当前格子的位置为初始的位置的时候,可是现在并没有设置初始位置的回溯目标所以:

    map[1][0].Iswall = False
    map[1][1].from_x = 0
    map[1][1].from_y = 1
    
    

    那么所有的代码就写好了

    接下来就是相当于是在修bug

    比如要防止别人输入的长或宽过小,防止输入的长或宽是偶数:

    if width_set<4 or height_set<4:
        width_set=11
        height_set=11
        print("输入的尺寸过小,已自动调节成,宽度:11,高度:11")
    if width_set%2 !=1:
        width_set +=1
        print("宽度请输入奇数,已自动矫正为:"+str(width_set))
    if height_set%2 !=1:
        height_set +=1
        print("高度请输入奇数,已自动矫正为:"+str(height_set))
    
    

    现在我们运行代码的时候基本上是没有问题了,但是,有的时候当我们把长和宽调的过大的时候会产生这样的错误
    在这里插入图片描述
    这是因为我们触发了Windows的保护系统,这个是为了防止我们的代码陷入死递归,不停下来,因此我们要设置系统允许的最大的递归次数

    import sys
    sys.setrecursionlimit(5000)
    
    

    这样大体上就写完了
    在下一篇文章里我会基于这个迷宫写关于寻路的算法效果如下
    在这里插入图片描述
    这个结束了以后还会再发一篇关于这个算法的不足和改进后的算法,效果如下:
    在这里插入图片描述

    展开全文
  • BFS(宽度优先算法

    2022-01-29 20:18:58
    宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它...

    1.BFS简介

         宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。换句话说,它并不考虑结果的可能位置,彻底地搜索整张图,直到找到结果为止。简单来说,bfs好像是一个耳听六路眼观八方的人,搜索时是一层一层的搜索的。BFS利用的数据结构是queue,空间复杂度为o(2^n),另外BFS可以用来解决最短路问题。BFS是一个从近到远的扩散过程。

    2.基本思想

       从初始状态S开始,利用规则,生成所有可能的状态。构成树的下一层节点,检查是否出现目标状态G,若未出现,就对该层所有状态节点,分别顺序利用规则。生成再下一层的所有状态节点,对这一层的所有状态节点检查是否出现G,若未出现,继续按上面思想生成再下一层的所有状态节点,这样一层一层往下展开。直到出现目标状态为止。

    3.算法步骤

    (1)把起始节点S线放到queue 表中克祥
      (2)如果queue是空表,则失败退出,否则继续。
      (3)在queue表中取最前面的节点node 移到 CL OSED 表中。(出队)
      (4)扩展node节点。若没有后继即叶节点),则转向(2)循环。
      (5)把node的所有后继节点放在queue表的末端。各后继结点指针指向node节点。(入队)
      (6)若后继节点中某一个是目标节点,则找到一个解,成功退出。否则转向(2)循环。

    4.例题

       BFS和DFS一样搜索框架比较多,所以我们也是来看两个经典例题

     4.1AcWing 844 走迷宫

    给定一个 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

    解题思路:这里需要注意只有所以边权重一样时,才能用BFS来求最短路。这个题是用BFS来求的,因为BFS是每次一层一层的搜索,因此第一次搜到的点就是最短路。BFS搜索如下图,一次一次的每次搜索都是看一下离自己最近的位置是否可以走。

     

    代码如下:

    #include<bits/stdc++.h>
    using namespace std;
    typedef pair<int,int>PLL;
    const int N=110;
     int n,m;
    int g[N][N];//存放起始图
    int d[N][N];//每一个点到起点的距离
    PLL q[N*N];//模拟队列
    int bfs()
    {
        int hh=0,tt=0;//定义队头和队尾
        q[0]={0,0};//定义起始位置
        memset(d,-1,sizeof d);//初始化每一个点为-1,表示没有走过
        d[0][0]=0;//表示0,0点已经走过
        int dx[4]={-1,0,1,0},dy[4]={0,1,0,-1};//用向量-1,0,1,0来表示每次走的方向
        while(hh<=tt)//队列不空
        {
            auto t =q[hh++];//取出队头元素
            for(int i=0;i<4;i++)//遍历四个方向
            {
                int x=t.first+dx[i],y=t.second+dy[i];//移动后的点
                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;
    }

    例题2 AcWing   845 八数码

    在一个 3×3 的网格中,1∼8 这 8 个数字和一个 x 恰好不重不漏地分布在这 3×3 的网格中。

    例如:

    1 2 3
    x 4 6
    7 5 8
    

    在游戏过程中,可以把 x 与其上、下、左、右四个方向之一的数字交换(如果存在)。

    我们的目的是通过交换,使得网格变为如下排列(称为正确排列):

    1 2 3
    4 5 6
    7 8 x
    

    例如,示例中图形就可以通过让 x 先后与右、下、右三个方向的数字交换成功得到正确排列。

    交换过程如下:

    1 2 3   1 2 3   1 2 3   1 2 3
    x 4 6   4 x 6   4 5 6   4 5 6
    7 5 8   7 5 8   7 x 8   7 8 x
    

    现在,给你一个初始网格,请你求出得到正确排列至少需要进行多少次交换。

    输入格式

    输入占一行,将 3×3 的初始网格描绘出来。

    例如,如果初始网格如下所示:

    1 2 3 
    x 4 6 
    7 5 8 
    

    则输入为:1 2 3 x 4 6 7 5 8

    输出格式

    输出占一行,包含一个整数,表示最少交换次数。

    如果不存在解决方案,则输出 −1−1。

    输入样例:

    2  3  4  1  5  x  7  6  8
    

    输出样例

    19

    解题思路:以下图为例,我们可以把每一种移动方式看作是一个节点,目标情况看作是终点。

     

    问题:

    1.怎么将一种情况看作是一个节点

    2.如何记录每一个状态的距离(即需移动的距离)

    3.队列怎么定义,dist数组怎么定义

    解决方案:将3*3矩阵转化成字符串

    队列可以用 queue<string>
    //直接存转化后的字符串
    dist数组用 unordered_map<string, int>
    //将字符串和数字联系在一起,字符串表示状态,数字表示距离 

     矩阵与字符串的转化

     

    代码如下:

    #include <iostream>
    #include <algorithm>
    #include <queue>
    #include <unordered_map>

    using namespace std;

    int bfs(string start)
    {
        //定义目标状态
        string end = "12345678x";
        //定义队列和dist数组
        queue<string> q;
        unordered_map<string, int> d;
        //初始化队列和dist数组
        q.push(start);
        d[start] = 0;
        //用向量表示移动方向
        int dx[4] = {1, -1, 0, 0}, dy[4] = {0, 0, 1, -1};

        while(q.size())
        {
            auto t = q.front();
            q.pop();
            //记录当前状态的距离,如果是最终状态则返回距离
            int distance = d[t];
            if(t == end) return distance;
            //查询x在字符串中的下标,然后转换为在矩阵中的坐标
            int k = t.find('x');
            int x = k / 3, y = k % 3;

            for(int i = 0; i < 4; i++)
            {
                //求转移后x的坐标
                int a = x + dx[i], b = y + dy[i];
                //当前坐标没有越界
                if(a >= 0 && a < 3 && b >= 0 && b < 3)
                {
                    //转移x
                    swap(t[k], t[a * 3 + b]);
                    //如果当前状态是第一次遍历,记录距离,入队
                    if(!d.count(t))
                    {
                        d[t] = distance + 1;
                        q.push(t);
                    }
                    //还原状态,为下一种转换情况做准备
                    swap(t[k], t[a * 3 + b]);
                }
            }
        }
        //无法转换到目标状态,返回-1
        return -1;
    }

    int main()
    {
        string c, start;
        //输入起始状态
        for(int i = 0; i < 9; i++)
        {
            cin >> c;
            start += c;
        }

        cout << bfs(start) << endl;

        return 0;
    }

    展开全文
  • 用二维数组存储迷宫(只存在一条路径),用广度优先搜索算法计算路径
  • 题目: 给定一个n*m的二维整数数组,用来表示一个迷宫,数组中只包含0或1,其中0表示可以走的路,1表示不可通过的墙壁。 最初,有一个人位于左上角(1, 1)处,已知该人每次可以向上、下、左、右任意一个方向移动一个...
  • 本文实例讲述了Python解决走迷宫问题算法。分享给大家供大家参考,具体如下: 问题: 输入n * m 的二维数组 表示一个迷宫 数字0表示障碍 1表示能通行 移动到相邻单元格用1步 思路: 深度优先遍历,到达每一个点,...
  • 广度优先搜索,也叫宽度优先搜索,从开始状态,到第一次能到达的状态,再从第一次能到达的状态到下一个能到达的状态,直到探索所有可到达的状态,其时间复杂度为O(状态数×转移的方式)。 广度优先搜索使用了队列的...
  • 迷宫问题 C代码 #include<stdio.h> typedef struct node{ int x; int y; int f; /*如果需要输出路径,则需要f */ int s; /* 步数 */ }node; int main() { node que[2501]; int a[51][51]...
  • 宽搜,即宽度优先搜索,是图的搜索算法之一。其别名又叫BFS,属于一种盲目搜寻法,目的是系统地展开并检查图中的所有节点,以找寻结果。 代码效果 输入一个宽高自定的迷宫,若走得通,输出最短路径步数; 若走不通,...
  • 宽度优先搜索-----解决迷宫最短路径问题 一、关于宽度优先搜索的知识 1.深度优先搜索利用栈进行计算,因此一般场景中采用递归的方式实现。 2.宽度优先搜索则利用队列进行计算,搜索时首先将初始状态添加到队列里,...
  • 宽度优先搜索算法

    千次阅读 2020-10-12 20:24:15
    宽度优先搜索算法算法简介实战练习 算法简介 宽度优先搜索又称广度优先搜索或横向优先搜索。该算法是一种图形搜索算法,该算法是从起点开始搜索然后一层一层的向下搜索,如果找到目标或者搜索完了全部的节点则算法...
  • 广度优先搜索算法三、实验代码和用于测试的迷宫1.实验代码2.测试迷宫2.1 maze1.txt2.2 maze2.txt2.3 maze3.txt四、实验结果1. maze1.txt2. maze2.txt3. maze3.txt五、结果分析总结 一、实验内容 下载mymaze.py文件...
  • 所谓深度优先算法,百科的解答是这样的深度优先搜索算法(Depth-First-Search),简称DFS,是搜索算法的一种。是沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所有边都己被探寻过,搜索将回溯到发现...
  • 深度优先搜索算法迷宫问题

    千次阅读 2019-02-15 18:07:37
    如图是一个矩形迷宫,需要从起点(1,1)走到终点(4,3),那么需要7步。 下面程序完成从起点(0,1)到终点(0,3)的最短距离,结果为12. #include &lt;stdio.h&gt; using namespace std; struct...
  • 迷宫算法,求迷宫起点到终点的最短路径
  • 一、算法原理 ...宽度优先搜索算法(Breadth First Search,BSF),思想是: 从图中某顶点v出发,首先访问定点v 在访问了v之后依次访问v的各个未曾访问过的邻接点; 然后分别从这些邻接点出发依次访...
  • 宽度优先搜索,即BFS,有时也叫做广度优先搜索。与深度优先搜索的一条路走到黑不同,它是先遍历离自己最近的一些点,然后逐步向更远的路径进行搜索。它利用的是队列来完成这一操作。在这道迷宫求解问题中它的时间...
  • 给定一个n*n的迷宫,要求利用广度优先和深度优先算法解决迷宫问题 问题分析: 对于此问题首先要明确搜索顺序 可以分为两种方法求解问题:1.广度优先算法2.深度优先算法 (1)对于深度优先算法来说:<如果规定...
  • 宽度优先搜索算法BFS

    2021-02-24 16:53:58
    例题 2.1最少步数 2.2Dungeon Master BFS(Breadth First Search 宽度优先搜索) 宽度优先搜索算法(又称广度优先搜索)是最简便的图的搜索算法之一,这一算法也是很多重要的图的算法的原型。其别名又叫BFS,属于一种...
  • 使用队列,层层递进,往下扩展。  5 4  0 0 1 0 ...(5,4是迷宫的行和列,0代表空地,1代表障碍物,1,1是起始位置,4,3 是需要到达的位置)  7   #include&lt;stdio.h&gt; struct no...
  • 迷宫算法宽度优先搜索Java实现 import java.util.ArrayList; import java.util.List; import java.util.Scanner; /** 5 5 1 1 0 1 1 0 1 0 1 0 0 1 1 1 0 0 0 1 1 0 1 0 1 1 1 * */ public class BfsTest { ...
  • 易语言最短路径走迷宫,BFS(宽度优先搜索) 易语言纯源码实现 简单搜索算法 。@qwb492859377。
  • 深度优先搜索算法 深度优先搜索算法(Depth-First-Search,简称DFS)是一种用于遍历或搜索树或图的算法。沿着树的深度遍历树的节点,尽可能深的搜索树的分支。当节点v的所在边都己被探寻过,搜索将回溯到发现节点v...
  • 问题引入 地图上有很多个城市,已知各城市之间距离(或者是所需时间,后面都用距离了),一般问题无外乎就是以下几个: 从某城市到其余所有城市的最短距离【单源...此算法仅供娱乐参考,实际不会用它的,因为算法复杂

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 1,486
精华内容 594
关键字:

宽度优先算法迷宫