【蓝桥OJ:BFS】2019省赛:迷宫 python实现

题目链接:https://www.lanqiao.cn/problems/602/learning/
思路:
1.基本算法:最短路径迷宫题采用BFS(广搜)算法
2.迷宫图的储存方法:使用二维列表逐行逐列储存地图mp
3.走迷宫应注意:
1)设置标记已走过的平行地图vis,设置走迷宫jued()函数,边界判断,用if来走迷宫;
2)储存路径的数据结构是重点,此处采用队列deque。为实现BFS需要一个空队列deque(run)来储存BFS过程:探索结点A时,判断一遍结点A的四个neighbor(相邻四点),储存能走的下一个结点入队run,随后pop将结点A弹出队列,如此往复就是BFS的过程;
4.字典序小技巧:每个结点的探图方向用‘D,L,R,U’的字典序顺序,这样BFS搜出来的第一条路径就是字典序最小的最短路径了
5.最短路径储存方法:前驱结点记录法:探图时用字典同时记录每个点的前驱结点
6.通过路径遍历四个方向来生成脚印

代码:

import  collections
s='''01010101001011001001010110010110100100001000101010
00001000100000101010010000100000001001100110100101
01111011010010001000001101001011100011000000010000
01000000001010100011010000101000001010101011001011
00011111000000101000010010100010100000101100000000
11001000110101000010101100011010011010101011110111
00011011010101001001001010000001000101001110000000
10100000101000100110101010111110011000010000111010
00111000001010100001100010000001000101001100001001
11000110100001110010001001010101010101010001101000
00010000100100000101001010101110100010101010000101
11100100101001001000010000010101010100100100010100
00000010000000101011001111010001100000101010100011
10101010011100001000011000010110011110110100001000
10101010100001101010100101000010100000111011101001
10000000101100010000101100101101001011100000000100
10101001000000010100100001000100000100011110101001
00101001010101101001010100011010101101110000110101
11001010000100001100000010100101000001000111000010
00001000110000110101101000000100101001001000011101
10100101000101000000001110110010110101101010100001
00101000010000110101010000100010001001000100010101
10100001000110010001000010101001010101011111010010
00000100101000000110010100101001000001000000000010
11010000001001110111001001000011101001011011101000
00000110100010001000100000001000011101000000110011
10101000101000100010001111100010101001010000001000
10000010100101001010110000000100101010001011101000
00111100001000010000000110111000000001000000001011
10000001100111010111010001000110111010101101111000'''

mp=[[int(i) for i in j ]for j in s.split('\n')]
vis=[[False for i in j ]for j in s.split('\n')]#标记访问
run=collections.deque()  #BFS用队列
path=[]  #路径
dire=[(0,1),(-1,0),(1,0),(0,-1)]  #字典序D,L,R,U


def jued(x,y):  #走迷宫函数
	if mp[y][x]==0 and vis[y][x]==False:
		return True
dic={}  #用字典记录前驱结点
def bfs():  #广搜
    run.append((0,0))
    while len(run)!=0:
        temp=0
        x=run[0][0]
        y=run[0][1]
        vis[0][0]=True
        for i in range(4):
                newx = x+dire[i][0]
                newy = y+dire[i][1]
                if 0<=newx<=49 and 0<=newy<=29:
                        if jued(newx,newy)==True:
                                vis[newy][newx]=True
                                run.append((newx,newy))
                                dic[(newx,newy)]=(x,y)
                                if newx==49 and newy==29 :return 0
        run.popleft()		
bfs()

def find_path(x,y):#递归串联出最短路径
        path.append((x,y))
        if x==y==0:
                return path
        else:
                return find_path(dic[(x,y)][0],dic[(x,y)][1])

find_path(49,29)
path=path[::-1]  #倒叙路径
step=collections.deque()  #脚印


for i in range(1,len(path)):#生成脚印
        for j in range(4):
                if path[i][0]==path[i-1][0]+dire[j][0] and path[i][1]==path[i-1][1]+dire[j][1]:
                      
                      if j==0:step.append('D')
                      elif j==1:step.append('L')
                      elif j==2:step.append('R')
                      elif j==3:step.append('U')
                      break


print(''.join(step))#输出格式



#DFS输出一条路径(并非最短)方法:
'''import sys
sys.setrecursionlimit(2000)
s='......'

mp=[[int(i) for i in j] for j in s.split('\n')]
vis=[[False for i in j]for j in s.split('\n')]
di=[[-1,0],[0,-1],[1,0],[0,1]]  #向左、上、右、下
path=[]
print(mp[29][49])
def dest(x,y):
    if x==49 and y==29:
        #True已到终点
        return True                
    else:return False
def check(x,y):
    if x in range(0,50) and y in range(0,30) and vis[y][x]==False and mp[y][x]==0 :#条件检查
        return True
    else : return False

def dfs(x,y):
    if dest(x,y):
        return True  #走到终点
    vis[y][x]=True
    for i in range(4):
        newx=x+di[i][0]
        newy=y+di[i][1]
        if check(newx, newy):
            if i==0 :
                path.append(('L',newx,newy))
                return dfs(newx,newy)
            if i==1 :
                path.append(('U',newx,newy))
                return dfs(newx,newy)
            if i==2 :
                path.append(('R',newx,newy))
                return dfs(newx,newy)
            if i==3 :
                path.append(('D',newx,newy))
                return dfs(newx,newy)
        else:continue
    path.pop() #回溯
    vis[path[-1][2]][path[-1][1]]=False
    return dfs(path[-1][1],path[-1][2])
dfs(0,0)
result=[]
for i in range(len(path)):
    result.append(path[i][0])
print(''.join(result))    '''

总结:
BFS算法是最短路径问题最基础的方法。此类搜索题书写的代码量较多,采用的数据结构较多,如这题列表、元组、字典都灵活运用到了,但思路明确,算法不算复杂。

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
基于Python实现迷宫搜索游戏源码+项目详细说明(课程作业) 该项目不过是一个平平无奇的小作业,基于python3.8开发,目前提供两种迷宫生成算法与三种迷宫求解算法,希望对大家的学习有所帮助。 这是python3.8,同时我们还包含了两个第三方库,这些我将会放在requirement.txt中。是的,我现在意识到它非常重要,因为跑别人代码没有它真的很容易环境冲突。 文件介绍 项目很简单,一共只有三个文件,所以如果是想要学习的朋友应该很容易可以梳理清楚文件的关系。 ui.py 是项目的UI设计以及运行入口,所有的逻辑都是基于此开发的; Generate.py 是项目中负责生成迷宫的,提供了DFS、PRIM两种生成方式,具体的逻辑一会会介绍; solve.py 是项目中负责迷宫求解的部分,提供了DFSBFS、A*三种迷宫求解方案。 生成算法逻辑实现 该部分介绍一下两个迷宫生成算法的主要逻辑。 DFS 生成迷宫 深度搜素算法构建迷宫。我在实现该算法的时候和网络上的方法略有出入,大体流程如下: 首先构建迷宫大小的两个矩阵,分别位记录迷宫形状的maze_map和记录迷宫访问状态的maze_state;同时还有一个记录DFS状态的memory列表。 将起点添加进上述三个空间中: 当memory列表不为空时,开始循环: 如果memory最后一个元素可以向外扩展:即与该元素相邻的元素存在未被访问过的元素,则将该元素添加进入列表中,如果有多个未被访问过的元素,则随机选择一个进入,来确保迷宫的随机性。并将添加进来的元素的maze_state标记为1。 如果memory最后一个元素无法向外扩展,则将该元素从memory中弹出。 这里需要注意的时,如何判断一个元素是否可以向外扩展呢?这里的判断条件如下: 不可以超出迷宫限定的大小范围; 扩展的点不能被访问过 被扩展的点不能联通两个两条路线,防止出现环; PRIM 生成迷宫 PRIM构建迷宫。该算法构建迷宫构建流程如下图所示: 构建一个迷宫大小的深度为5的向量,分别包含访问标记、四周墙体的状态。同时,包含一个memory来记忆以及打通的墙体; 将起点添加进去; 当memory长度不为空的时候,开始循环: 随机从memory中抽取一个节点m; 获取节点m所有合法的探索方向; 如果探索方向合法且新的节点未被访问过则添加进入memory,并标记为访问过,否则弹出memory。 同样的,这里的合法的探索方向也有限制条件: 不可以超出迷宫限定的大小范围; 扩展的点不能被访问过 求解路径算法逻辑实现 在完成了迷宫设计后,接下来开始设计求解方法。 DFS 迷宫求解 DFS是经典的迷宫求解算法,通过深度搜索探索全部路径,直到到达终点,这在仅有一条通路的情况下是还不错的。但通常现实环境是复杂的,存在多条通路的,在这种情况下DFS很难获得最优路径。 接下来介绍DFS实现流程: 建立地图的标记坐标,以及存放以及走过位置的memory; 开始循环: 如果当前坐标无法扩展新的坐标,则弹出; 如果当前坐标可以扩展新的坐标,则将新的坐标入栈,且新坐标的标志位设置为1; 若新的坐标为终点时,结束循环。 同样的,算法方向的选择也是核心问题之一: 新的坐标未超出地图位置; 新的坐标不是墙体且未被访问过。 BFS 迷宫求解 BFS也是常用的迷宫问题求解算法,通过广度优先的方法,通常来说广度优先搜索在路径搜索中可以得到最优解。如果迷宫有且仅有唯一解,该算法所探索的格子一般远高于DFS探索的空间,但如果迷宫中有多个路径存在时,该算法可以获得最优解。接下来时BFS算法逻辑: 建立地图的标记坐标,以及存放以及走过位置的memory,同时我们还需要一个存放每一次迭代的所有坐标的列表; 开始循环: 对坐标列表中的所有位置进行迭代,将可以到达的坐标添加到新的坐标列表中,并更新memory和标志位; 检查是否到达终点,到达则跳出循环。 在方向的统计上,同BFS一样。 A* 迷宫求解 DFS虽然可以求得最优路径,但由于其的复杂度极高,且遍历空间极大的问题,在实际使用中通常不被采用;A*算法是在其后的佼佼者,通过启发式搜索的方式,在程序运行的阶段,对于其当前位置的移动损耗和预计损耗作为评估指标,来实现剪枝的作用。其流程如下所示: 建立地图的标记坐标、存放以及走过位置的memory、损耗优先队列cost; 开始循环: 对cost最小的元素进行拓展; 如果拓展结果为空,则弹出; 如果拓展结果存在值,则计算新节点的cost,并添加入cost队列中。 检查是否到达终点,到达则跳出循环。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

汤米尼克

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值