使用python求解迷宫问题的三种实现方法


Posted in Python onMarch 17, 2022

前言

在迷宫问题中,给定入口和出口,要求找到路径。本文将讨论三种求解方法,递归求解、回溯求解和队列求解。

在介绍具体算法之前,先考虑将迷宫数字化。这里将迷宫用一个二维的list存储(即list嵌套在list里),将不可到达的位置用1表示,可到达的位置用0表示,并将已经到过的位置用2表示。

使用python求解迷宫问题的三种实现方法

递归求解

递归求解的基本思路是:

  • 每个时刻总有一个当前位置,开始时这个位置是迷宫人口。
  • 如果当前位置就是出口,问题已解决。
  • 否则,如果从当前位置己无路可走,当前的探查失败,回退一步。
  • 取一个可行相邻位置用同样方式探查,如果从那里可以找到通往出口的路径,那么从当前位置到出口的路径也就找到了。

在整个计算开始时,把迷宫的人口(序对)作为检查的当前位置,算法过程就是:

  • mark当前位置。
  • 检查当前位置是否为出口,如果是则成功结束。
  • 逐个检查当前位置的四邻是否可以通达出口(递归调用自身)。
  • 如果对四邻的探索都失败,报告失败。
dirs=[(0,1),(1,0),(0,-1),(-1,0)] #当前位置四个方向的偏移量
path=[]              #存找到的路径
 
def mark(maze,pos):  #给迷宫maze的位置pos标"2"表示“倒过了”
    maze[pos[0]][pos[1]]=2
 
def passable(maze,pos): #检查迷宫maze的位置pos是否可通行
    return maze[pos[0]][pos[1]]==0
 
def find_path(maze,pos,end):
    mark(maze,pos)
    if pos==end:
        print(pos,end=" ")  #已到达出口,输出这个位置。成功结束
        path.append(pos)
        return True
    for i in range(4):      #否则按四个方向顺序检查
        nextp=pos[0]+dirs[i][0],pos[1]+dirs[i][1]
        #考虑下一个可能方向
        if passable(maze,nextp):        #不可行的相邻位置不管
            if find_path(maze,nextp,end):#如果从nextp可达出口,输出这个位置,成功结束
                print(pos,end=" ")
                path.append(pos)
                return True
    return False
 
def see_path(maze,path):     #使寻找到的路径可视化
    for i,p in enumerate(path):
        if i==0:
            maze[p[0]][p[1]] ="E"
        elif i==len(path)-1:
            maze[p[0]][p[1]]="S"
        else:
            maze[p[0]][p[1]] =3
    print("\n")
    for r in maze:
        for c in r:
            if c==3:
                print('\033[0;31m'+"*"+" "+'\033[0m',end="")
            elif c=="S" or c=="E":
                print('\033[0;34m'+c+" " + '\033[0m', end="")
            elif c==2:
                print('\033[0;32m'+"#"+" "+'\033[0m',end="")
            elif c==1:
                print('\033[0;;40m'+" "*2+'\033[0m',end="")
            else:
                print(" "*2,end="")
        print()
 
if __name__ == '__main__':
    maze=[[1,1,1,1,1,1,1,1,1,1,1,1,1,1],\
          [1,0,0,0,1,1,0,0,0,1,0,0,0,1],\
          [1,0,1,0,0,0,0,1,0,1,0,1,0,1],\
          [1,0,1,0,1,1,1,1,0,1,0,1,0,1],\
          [1,0,1,0,0,0,0,0,0,1,1,1,0,1],\
          [1,0,1,1,1,1,1,1,1,1,0,0,0,1],\
          [1,0,1,0,0,0,0,0,0,0,0,1,0,1],\
          [1,0,0,0,1,1,1,0,1,0,1,1,0,1],\
          [1,0,1,0,1,0,1,0,1,0,1,0,0,1],\
          [1,0,1,0,1,0,1,0,1,1,1,1,0,1],\
          [1,0,1,0,0,0,1,0,0,1,0,0,0,1],\
          [1,1,1,1,1,1,1,1,1,1,1,1,1,1]]
    start=(1,1)
    end=(10,12)
    find_path(maze,start,end)
    see_path(maze,path)

代码中see_path函数可以在控制台直观打印出找到的路径,打印结果如下:

使用python求解迷宫问题的三种实现方法

S是入口位置 ,E是出口位置,*代表找到的路径,#代表探索过的路径。

回溯求解

在回溯解法中,主要是用栈来存储可以探索的位置。利用栈后进先出的特点,在一条分路上探索失败时,回到最近一次存储的可探索位置。这是一种深度优先搜索的方法。

def maze_solver(maze,start,end):
    if start==end:
        print(start)
        return
    st=SStack()
    mark(maze,start)
    st.push((start,0))             #入口和方向0的序对入栈
    while not st.is_empty():      #走不通时回退
        pos,nxt=st.pop()           #取栈顶及其检查方向
        for i in range(nxt,4):     #依次检查未检查方向,算出下一位置
            nextp = pos[0] + dirs[i][0], pos[1] + dirs[i][1]
            if nextp==end:
                print_path(end,pos,st)  #到达出口,打印位置
                return
            if passable(maze,nextp):    #遇到未探索的新位置
                st.push((pos,i+1))      #原位置和下一方向入栈
                mark(maze,nextp)
                st.push((nextp,0))      #新位置入栈
                break                   #退出内层循环,下次迭代将以新栈顶作为当前位置继续
    print("找不到路径")

队列求解

队列求解算法中,以队列存储可以探索的位置。利用队列先进先出的特点,实现在每个分支上同时进行搜索路径,直到找到出口。这是一种广度优先搜索的方法。

def maze_solver_queue(maze,start,end):
   path.append(start)
   if start==end:
       print("找到路径")
       return
   qu=SQueue()
   mark(maze,start)
   qu.enqueue(start)                #start位置入队
   while not qu.is_empty():        #还有候选位置
       pos=qu.dequeue()             #取出下一位置
       for i in range(4):           #检查每个方向
           nextp = pos[0] + dirs[i][0], pos[1] + dirs[i][1]
           if passable(maze,nextp): #找到新的探索方向
               if nextp==end:       #是出口,成功
                   print("找到路径")
                   path.append(end)
                   return
               mark(maze,nextp)
               qu.enqueue(nextp)    #新位置入队
               path.append(nextp)
 
   print("未找到路径")

但队列求解方法,不能直接得出找到的具体路径,要得到找到的路径还需要其他存储结构(如链表)。

总结

到此这篇关于使用python求解迷宫问题的三种实现方法的文章就介绍到这了,更多相关python求解迷宫问题内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Python 相关文章推荐
Python迭代用法实例教程
Sep 08 Python
对Python新手编程过程中如何规避一些常见问题的建议
Apr 01 Python
python实现将内容分行输出
Nov 05 Python
关于python的bottle框架跨域请求报错问题的处理方法
Mar 19 Python
Python外星人入侵游戏编程完整版
Mar 30 Python
Python 加密的实例详解
Oct 09 Python
Python for循环中的陷阱详解
Jul 13 Python
使用python将时间转换为指定的格式方法
Nov 12 Python
Pyqt5 实现跳转界面并关闭当前界面的方法
Jun 19 Python
Python内置方法实现字符串的秘钥加解密(推荐)
Dec 09 Python
2020年10款优秀的Python第三方库,看看有你中意的吗?
Jan 12 Python
神经网络训练采用gpu设置的方式
Mar 03 Python
Python超详细分步解析随机漫步
yolov5返回坐标的方法实例
Mar 17 #Python
PyTorch中的torch.cat简单介绍
Mar 17 #Python
Python Pygame实战在打砖块游戏的实现
python超详细实现完整学生成绩管理系统
Mar 17 #Python
Python Pygame实战之塔防游戏的实现
pytorch中的 .view()函数的用法介绍
Mar 17 #Python
You might like
浅析Dos下运行php.exe,出现没有找到php_mbstring.dll 错误的解决方法
2013/06/29 PHP
探讨:web上存漏洞及原理分析、防范方法
2013/06/29 PHP
如何使用纯PHP实现定时器任务(Timer)
2015/07/31 PHP
PDO的安全处理与事物处理方法
2016/10/31 PHP
使用WAMP搭建PHP本地开发环境
2017/05/10 PHP
PHP array_reduce()函数的应用解析
2018/10/28 PHP
JSON无限折叠菜单编写实例
2013/12/16 Javascript
JavaScript 事件对象介绍
2015/04/13 Javascript
js获取微信版本号的方法
2015/05/12 Javascript
纯CSS3代码实现滑动开关效果
2015/08/19 Javascript
基于jQuery实现网页打印功能
2015/12/01 Javascript
浅谈Javascript数组(推荐)
2016/05/17 Javascript
jQuery封装的屏幕居中提示信息代码
2016/06/08 Javascript
JavaScript DOM节点操作方法总结
2016/08/23 Javascript
jQuery弹出层插件popShow用法示例
2017/01/23 Javascript
bootstrap datepicker插件默认英文修改为中文
2017/07/28 Javascript
vue template中slot-scope/scope的使用方法
2018/09/06 Javascript
Next.js项目实战踩坑指南(笔记)
2018/11/29 Javascript
基于小程序请求接口wx.request封装的类axios请求
2020/07/02 Javascript
vue 验证两次输入的密码是否一致的方法示例
2020/09/29 Javascript
python 发送和接收ActiveMQ消息的实例
2019/01/30 Python
如何在python中实现随机选择
2019/11/02 Python
opencv3/C++实现视频背景去除建模(BSM)
2019/12/11 Python
Python GUI自动化实现绕过验证码登录
2020/01/10 Python
python如何使用Redis构建分布式锁
2020/01/16 Python
Django与pyecharts结合的实例代码
2020/05/13 Python
django创建css文件夹的具体方法
2020/07/31 Python
澳大利亚领先的女性运动服品牌:Lorna Jane
2020/06/19 全球购物
亿阳信通股份有限公司笔试题(C#)
2016/03/04 面试题
Java面试题:说出如下代码的执行结果
2015/10/30 面试题
2014年乡镇卫生院工作总结
2014/11/24 职场文书
ktv服务员岗位职责
2015/02/09 职场文书
青年志愿者服务活动总结
2015/05/06 职场文书
2016会计专业自荐信范文
2016/01/28 职场文书
分享几个JavaScript运算符的使用技巧
2021/04/24 Javascript
pytorch分类模型绘制混淆矩阵以及可视化详解
2022/04/07 Python