第十届蓝桥杯-试题E:迷宫(python)

目录

题目    信息

题目    答案

题目    思路

题目    解析

题目    拓展


 

  • 题目    信息

  • 题目    答案

RRDDDDDDRRRRRRRRRDDLDDDLDLLLDDLLDDDLDDRDDRRDDLLLDDRDRDRRRRDRDRRRURURRURRUULUUULLUUUULLLUURRRRUUUULLULUUUUUUURUURRRRDDDRRDRRURRRRRRDRDDDDRRUURRURRDRDRDDDDDDDDDDDDRDDLDDDRRRDRRRRRRRURRDDDD

  • 题目    思路

这个题目是我学习   广度优先搜索   之后做的第一个题目,想了的比较久,但是思路还是很清晰。

主要就是按照广度优先搜索的方法来,具体的思路都在我的另外一片博客里面有的:

06_第六章 广度优先搜索(bfs)

从起点开始,建立一个队列,把从起点开始可以走的路都把ta加入到队列里面来,最后一定是可以找到出口的

建模的思路如下:

  1. 构建位置信息,将01的位置转换成具体的坐标,同时建立围墙,方便搜索
  2. 通过广度优先搜索的方法来找道路径
  3. 将路径转化成UDLR的方位信息,输出答案
  • 题目    解析

import collections
#导入collections库,会用到其中deque模块(队列)
f=open("maze.txt","r")
#打开文件(该文件和py文件在同一目录下面,否则应当改成文件的绝对路径)
s=f.readlines()
#读取文件的所有行,形成一个列表,每一行为一个元素
#---------------------------------------------------------
position={}
#建立坐标位置对应0/1的字典
#先建围墙的坐标,由于1代表障碍,所以围墙设为1
for y_wall in range(0,32):
    position[(0,y_wall)]='1'
    position[(51,y_wall)]='1'
for x_wall in range(0,52):
    position[(x_wall,0)]='1'
    position[(x_wall,31)]='1'
y=1
#y位置的初始值
for y_position in s:
    #遍历s中的每一行
    for xy_index in range(len(y_position)-1):
        #xy_index:0,1,2...49
        position[(xy_index+1,y)]=y_position[xy_index]
        #读取每一个0/1位置的坐标,将其加入到字典中去
    y=y+1
    #每读取一行之后,下一行y位置的值加1   
#上面程序运行之后,01文件的每个点的坐标建立完毕,存储在字典position中
#---------------------------------------------------------
#下面开始对每个点开始搜索并且开始记录
m_deque=collections.deque()
#创建队列
start=(1,1)
end=(50,30)
checked_position=[]
#记录检查过的点的坐标信息的一个列表
m_deque.append(start)
#把起点加入到搜索队列中
while m_deque:
    #只要队列不空,就继续搜索
    to_check_position=m_deque.popleft()
    #把队列的第一个位置拿出来检查
    if to_check_position not in checked_position:
        #如果这个点(坐标)没有被检查过
        if to_check_position==end:
            print("ok!")
            break
            #如果这个点为出口的点的坐标,那么输出ok,同时循环结束
        else:
            #否则循环继续
            checked_position.append(to_check_position)
            #记录已经检查过的坐标
            up_position=(to_check_position[0],to_check_position[1]-1)
            down_position=(to_check_position[0],to_check_position[1]+1)
            left_position=(to_check_position[0]-1,to_check_position[1])
            right_position=(to_check_position[0]+1,to_check_position[1])
            #返回正在被检查的坐标的上下左右点位置的坐标
            #不能用elif!!!!!!!!!!!!只能每个都是if
            if position.get(up_position)=="0" and up_position not in checked_position:
                m_deque.append(up_position)
            #如果这个上面的点的坐标代表的是0,而且这个点坐标不在被检查过的列表里面,那么就把这个点的坐标位置加入到队列当中,下面同理
            if position.get(down_position)=="0" and down_position not in checked_position:
                m_deque.append(down_position)     
            if position.get(left_position)=="0" and left_position not in checked_position:
                m_deque.append(left_position)
            if position.get(right_position)=="0" and right_position not in checked_position:
                m_deque.append(right_position)
all_line=checked_position+[end]
#这个all_line表示记录过的点,再加上出口这个点(就是说我这个程序从起点到终点它到过了什么地方,那么接下来就会通过这个列表找出迷宫的路)
#---------------------------------------------------------
#寻找出那条从起点到终点的路径
every_end=(end)
#寻找从终点开始,往前找
line=[]
#路径坐标的列表
line_dulr=[]
#路径上下左右方向的列表
while every_end!=start:
    #只要找到的这个点不是起点,那么就继续找
    up_xy=(every_end[0],every_end[1]-1)
    down_xy=(every_end[0],every_end[1]+1)
    left_xy=(every_end[0]-1,every_end[1])
    right_xy=(every_end[0]+1,every_end[1])
    #返回这个被找的点的上下左右的坐标信息
    #注意这个下面必须要用elif!!!!!!!!!不能用都用if!!!!!!
    if position.get(up_xy)=="0" and up_xy in all_line:
        #如果这个点的上面点是0(表示可以走的路),而且这个点是被记录过的(表示这个点就是路径中的一个点)
        index=all_line.index(up_xy)
        #返回这个点在列表中的位置
        all_line=all_line[:index]
        #更新这个列表,就是说这个列表的最后一个元素是该点,那么下次再往前找位置的时候,眼光想起看就行了
        line.append(up_xy)
        #既然这个点是的话,那么就把这个点添加到最终的路径里面去
        line_dulr.append("D")
        #由于是反向走的,所以上面的这个坐标就要往下走
        every_end = up_xy
        #更新这个节点,然后从这个节点开始继续向前走   
    elif position.get(down_xy)=="0" and down_xy in all_line:
        index=all_line.index(down_xy)
        all_line=all_line[:index]
        line.append(down_xy)
        every_end=down_xy
        line_dulr.append("U")
    elif position.get(left_xy)=="0" and left_xy in all_line:
        index=all_line.index(left_xy)
        all_line=all_line[:index]
        line.append(left_xy)
        every_end=left_xy
        line_dulr.append("R")
    elif position.get(right_xy)=="0" and right_xy in all_line:
        index=all_line.index(right_xy)
        all_line=all_line[:index]
        line.append(right_xy)
        every_end=right_xy
        line_dulr.append("L")
    
#print(line)
#路线的坐标
#print(line_dulr)
line_s=""
for i in line_dulr:
    line_s=line_s+i
#把列表中的每个元素全都连接起来
print(line_s[::-1])
#输出答案,注意要反向一下,因为之前是倒着走的
  • 题目    拓展

为了更加清晰的表达出,程序里面在从终点向起点找路径的那段代码里面有一个不用  if  而用  elif  的地方,我这里特别说明一下  if  和  elif  以及  if  和  if  连用的区别,下面的代码可以好形象表现出来:

if ---- if  :

a=1
b=2
c=3
if a==1:
    print("a")
if b==2:
    print("b")
if c==3:
    print("c")

#输出
a
b
c

if ---- elif :

a=1
b=2
c=3
if a==1:
    print("a")
elif b==2:
    print("b")
elif c==3:
    print("c")

#输出
a

另外,我用海龟花了一下迷宫的图,方便大家直观感受(上下有点颠倒,但是不妨碍理解问题所在)

#海龟画迷宫
import turtle as t
t.hideturtle()
t.Turtle().screen.delay(0)
#快速画图,不然等的太久了
#画黑色的方块--围墙(障碍)
#为了更加清晰的表现出来,所有的位置或者什么尺寸都放大了十倍
def squure():
    t.color('black')
    t.begin_fill()
    t.setheading(0)
    t.fd(10)
    t.setheading(270)
    t.fd(10)
    t.setheading(180)
    t.fd(10)
    t.setheading(90)
    t.fd(10)
    t.end_fill()
#画红色方块--路线
def squurered():
    t.color('red')
    t.begin_fill()
    t.setheading(0)
    t.fd(10)
    t.setheading(270)
    t.fd(10)
    t.setheading(180)
    t.fd(10)
    t.setheading(90)
    t.fd(10)
    t.end_fill()
#画出迷宫的地图
for i in position:
    if position.get(i)=="1":
        t.penup()
        t.goto(int(i[0])*10,int(i[1])*10)
        t.pd()
        squure()
#在迷宫中画出路线
for i in line:
    t.penup()
    t.goto(int(i[0])*10,int(i[1])*10)
    t.pd()
    squurered()

大家感受一下画出来的效果:

 

(正确的)代码中用的是 if 和 elif :

 

(错误的)代码中用的是 if 和 if :

有些地方多走了

 

 

要是代码中有什么问题,或是没有理解的部分欢迎大家在下面评论,或者是私信我!

 

 

 

 

 

 

评论 7
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值