使用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的净值数据接口调用示例分享
Mar 15 Python
Python教程之全局变量用法
Jun 27 Python
Python对文件和目录进行操作的方法(file对象/os/os.path/shutil 模块)
May 08 Python
Python队列的定义与使用方法示例
Jun 24 Python
浅谈Python中的可变对象和不可变对象
Jul 07 Python
python使用itchat库实现微信机器人(好友聊天、群聊天)
Jan 04 Python
Python字符串、列表、元组、字典、集合的补充实例详解
Dec 20 Python
已安装tensorflow-gpu,但keras无法使用GPU加速的解决
Feb 07 Python
python对接ihuyi实现短信验证码发送
May 10 Python
python七种方法判断字符串是否包含子串
Aug 18 Python
最新版 Windows10上安装Python 3.8.5的步骤详解
Nov 28 Python
python drf各类组件的用法和作用
Jan 12 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
DEDE采集大师官方留后门的删除办法
2011/01/08 PHP
PHP7.1新功能之Nullable Type用法分析
2016/09/26 PHP
use jscript Create a SQL Server database
2007/06/16 Javascript
Mootools 1.2教程 输入过滤第二部分(字符串)
2009/09/15 Javascript
前端开发的开始---基于面向对象的Ajax类
2010/09/17 Javascript
jQuery对象和Javascript对象之间转换的实例代码
2013/03/20 Javascript
关于IE中getElementsByClassName不能用的问题解决方法
2013/08/26 Javascript
jquery easyui滚动条部分设置介绍
2013/09/12 Javascript
jquery mobile事件多次绑定示例代码
2013/09/13 Javascript
JavaScript?Apple设备检测示例代码
2013/11/15 Javascript
使表格的标题列可左右拉伸jquery插件封装
2014/11/24 Javascript
node.js中的querystring.stringify方法使用说明
2014/12/10 Javascript
JavaScript判断一个字符串是否包含指定子字符串的方法
2015/03/18 Javascript
jquery用ajax方式从后台获取json数据后如何将内容填充到下拉列表
2015/08/26 Javascript
Javascript动画效果(2)
2016/10/11 Javascript
BootStrap table删除指定行的注意事项(笔记整理)
2017/02/05 Javascript
Ajax验证用户名或昵称是否已被注册
2017/04/05 Javascript
JavaScript时间戳与时间日期间相互转换
2017/12/11 Javascript
如何使用less实现随机下雪动画详解
2019/01/02 Javascript
利用Bootstrap Multiselect实现下拉框多选功能
2019/04/08 Javascript
JS图片预加载三种实现方法解析
2020/05/08 Javascript
python用户管理系统的实例讲解
2017/12/23 Python
Python3 虚拟开发环境搭建过程(图文详解)
2020/01/06 Python
2020新版本pycharm+anaconda+opencv+pyqt环境配置学习笔记,亲测可用
2020/03/24 Python
给Django Admin添加验证码和多次登录尝试限制的实现
2020/07/26 Python
python 调整图片亮度的示例
2020/12/03 Python
Python类型转换的魔术方法详解
2020/12/23 Python
HTML5 History API 实现无刷新跳转
2016/01/11 HTML / CSS
FC-Moto西班牙:摩托车手最大的购物场所之一
2019/04/11 全球购物
客服文员岗位职责
2013/11/29 职场文书
写自荐信要注意什么
2013/12/26 职场文书
2015年青年志愿者工作总结
2015/05/20 职场文书
详解Python 3.10 中的新功能和变化
2021/04/28 Python
OpenCV-Python实现图像平滑处理操作
2021/06/08 Python
Java Spring 控制反转(IOC)容器详解
2021/10/05 Java/Android
一文了解Java动态代理的原理及实现
2022/07/07 Java/Android