使用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 相关文章推荐
DJANGO-ALLAUTH社交用户系统的安装配置
Nov 18 Python
Python 多线程实例详解
Mar 25 Python
浅谈使用Python变量时要避免的3个错误
Oct 30 Python
Python实现统计给定列表中指定数字出现次数的方法
Apr 11 Python
Python利用heapq实现一个优先级队列的方法
Feb 03 Python
Python3+OpenCV2实现图像的几何变换(平移、镜像、缩放、旋转、仿射)
May 13 Python
简单了解django文件下载方式
Feb 10 Python
使用python处理题库表格并转化为word形式的实现
Apr 14 Python
PyPDF2读取PDF文件内容保存到本地TXT实例
May 12 Python
Python 连接 MySQL 的几种方法
Sep 09 Python
python 通过使用Yolact训练数据集
Apr 06 Python
python中24小时制转换为12小时制的方法
Jun 18 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
Admin generator, filters and I18n
2011/10/06 PHP
PHP json_decode函数详细解析
2014/02/17 PHP
Laravel 5框架学习之向视图传送数据(进阶篇)
2015/04/08 PHP
php英文单词统计器
2016/06/23 PHP
PHP多进程编程实例详解
2017/07/19 PHP
PHP实现正则匹配所有括号中的内容
2018/06/22 PHP
兼容IE/Firefox/Opera/Safari的检测页面装载完毕的脚本Ext.onReady的实现
2009/07/14 Javascript
理解Javascript_09_Function与Object
2010/10/16 Javascript
提升PHP安全:8个必须修改的PHP默认配置
2014/11/17 Javascript
多种jQuery绑定事件的实现方式
2016/06/13 Javascript
微信小程序 闭包写法详细介绍
2016/12/14 Javascript
jQuery实现的form转json经典示例
2017/10/10 jQuery
node文件批量重命名的方法示例
2017/10/23 Javascript
仿iPhone通讯录制作小程序自定义选择组件的实现
2019/05/23 Javascript
Vue常用的全选/反选的示例代码
2020/02/19 Javascript
[48:30]LGD vs infamous Supermajor小组赛D组 BO3 第一场 6.3
2018/06/04 DOTA
在Python中用split()方法分割字符串的使用介绍
2015/05/20 Python
python使用psutil模块获取系统状态
2016/08/27 Python
Python进阶之使用selenium爬取淘宝商品信息功能示例
2019/09/16 Python
pandas数据处理之绘图的实现
2020/06/15 Python
python中元组的用法整理
2020/06/15 Python
Python利用pip安装tar.gz格式的离线资源包
2020/09/14 Python
Python datetime模块的使用示例
2021/02/02 Python
CSS3 animation实现简易幻灯片轮播特效
2016/09/27 HTML / CSS
群众路线剖析材料
2014/02/02 职场文书
教师节商场活动方案
2014/02/13 职场文书
个人债务授权委托书
2014/10/17 职场文书
中学教师个人总结
2015/02/10 职场文书
2015年数学教师工作总结
2015/05/20 职场文书
行政二审代理词
2015/05/25 职场文书
宿舍管理制度范本
2015/08/07 职场文书
导游词之无锡梅园
2019/11/28 职场文书
Java各种比较对象的方式的对比总结
2021/06/20 Java/Android
如何开启Apache,Nginx和IIS服务器的GZIP压缩功能
2022/04/29 Servers
Python 匹配文本并在其上一行追加文本
2022/05/11 Python
Python使用openpyxl模块处理Excel文件
2022/06/05 Python