BFS(宽度优先算法)走迷宫输出最少步数,最短路径和对应的动作(整合版)


示例:

输入:

5 5 
1 0 1 1 0
1 1 0 1 1 
0 1 0 1 1
1 1 1 1 1
1 0 0 0 1
1 1 5 5 

输出:

8
(0, 0),(1, 0),(1, 1),(2, 1),(3, 1),(3, 2),(3, 3),(3, 4),(4, 4)
D,R,D,D,R,R,R,D


代码:

from queue import Queue
n,m=map(int ,input().split())   #长度和宽度
g=[list(map(int,input().split()))for i in range(n)] #g是迷宫地图 1是可以走,0是障碍物
dir=[[-1,0],[1,0],[0,-1],[0,1]]       #dir是方向数组
dir_letter=['U','D','L','R']          #dir_letter是对应的方向,up,down,left,right
path=[]                               #path,存所有走过的路径,(x,y)
dirpath={}                          #dir_path存每一步的dir_letter,上一步到这一步怎么走的,U,D,L或者,R
father={}                             #father,是字典,存这一步的上一步是哪一个
vis=[[0 for i in range(m)]for i in  range(n)]  #vis的作用有两个,一个是筛选,没有走过的点都是0,一个是记录,记录到这一步的步数
x1,y1,x2,y2=map(int,input().split())      #x1,y1,x2,y2是入口和出口
q=Queue()                              #建立队列
def ins(x,y):                          #ins函数,看是否在迷宫以内防止出界
    if 0<=x<=n-1 and 0<=y<=m-1:
        return 1
    else:
        return 0
def bfs(x,y):                         #bfs主函数,x,y是入口
    global path,father,dirpath,vis    #定义全局变量,这是python和c++的区别之一,pyhon不定义会报错
    q.put([x,y])                      #先把入口入队列
    vis[x][y]=1                       #入口已经走过,所以vis为1,但是现在还没有走路,步数为0,所以最后返回值应该减一
    father[(x,y)]=0                  #入口上一个没有结点,为0  (None 和is not None对应),这里改成None,下面要改为 while cur is not None
    while q:                         #当队列不为空
        (nx,ny)=q.get()                #get(),出队,返回出队值,有没有()都可以
        if nx==x2-1 and ny==y2-1:      #如果到了终点
            cur=nx,ny                  
            while cur:                 #开始从终点找到起点路径(起点cur==0)
                path.append(cur)  
                cur=father[cur]
            path=path[::-1]           #倒转,得到真正路径
            break
        for i in range(4):            #四个方向遍历
            dx=nx+dir[i][0]
            dy=ny+dir[i][1]
            if ins(dx,dy)and vis[dx][dy]==0 and g[dx][dy]==1: #条件判断,在迷宫内,没有走过,不是墙壁可以走
                q.put([dx,dy])                        #入队
                vis[dx][dy]=vis[nx][ny]+1             #步数+1
                dirpath[(dx,dy)]=dir_letter[i]        #保存这一步是怎么走过来的
                father[(dx,dy)]=nx,ny                 #保存上一步是在哪里
    return vis[x2-1][y2-1]-1                          #返回走了多少步
print(bfs(x1-1,y1-1))                                 #输出走了多少步
for i in range(len(path)-1):            #输出路径
    print(path[i],end=",")
print(path[len(path)-1])
for i in path[1:len(path)-1]:           #输出动作
    print(dirpath[i],end=",")
print(dirpath[path[len(path)-1]])

测试用例

5 5 
1 0 1 1 0
1 1 0 1 1 
0 1 0 1 1
1 1 1 1 1
1 0 0 0 1
1 1 5 5     

以下一段话取自他人博客bfs
其实对于BFS来说,while里面的for循环更像是一种分身机制; 假如你现在有一只老鼠(代码里的cur)帮你走迷宫。当它遇到一个二叉分叉口(代码里的四个方向)的时候,他不会去选择其中一个去走,而是变出两个分身(代码里的next_pos)替它去走(之后自己保持原地不动,在队列里面它就是出队了,相当于在之后的搜索里面起不到任何作用)。这样的话,每碰到一个分叉口就变出更多的分身。这里的分叉口其实就是对于我们迷宫中的每一个位置,而分叉口的个数则是当前能走的方向数(没有走过且不是墙且在地图内)。对于每一时刻的老鼠(其实每一时刻的所有老鼠,都是上一时刻所有老鼠的分身), 我们让它们每次只走一步。这样子就能保证在任意时刻每个老鼠所走的步数是相同的,那么只要在某个时刻有一只老鼠到达终点, 那它的路径一定就是最短的。这就是为什么BFS总能找到最短路径。那如何保存这个最短路径呢?我们知道,每一个老鼠都是由之前的某个老鼠分身而来的,那么我们只需要记录每个老鼠是由谁分身而来的就可以了。这样子,我们抓到最后一只找到出口的老鼠,不断地从它身上寻找它的源体,最终就能找到一开始放在入口的那只老鼠。然后我们再把这个过程倒过来,那么就得到了从入口到出口的一个最短路径了,这就是BFS的全过

受益匪浅
 

  • 2
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值