题目
给一个二维列表,表示迷宫(0表示通道,1表示围墙)。给出算法,求一条走出迷宫的路径。
方法一 :使用栈 -- 深度优先搜索
方法:回溯法
思路:从一个节点开始,任意找下一个能走的点,当找不到能走的点时,退回上一个点寻找是否有其他方向的点。
使用栈存储当前路径。
示例代码如下:
maze = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 1, 0, 0, 0, 1, 0, 1],
[1, 0, 0, 1, 0, 0, 0, 1, 0, 1],
[1, 0, 0, 0, 0, 1, 1, 0, 0, 1],
[1, 0, 1, 1, 1, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 1, 0, 0, 0, 0, 1],
[1, 0, 1, 0, 0, 0, 1, 1, 0, 1],
[1, 0, 1, 1, 1, 0, 1, 1, 0, 1],
[1, 1, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
]
dirs = [
lambda x, y: (x + 1, y), # 上
lambda x, y: (x - 1, y), # 下
lambda x, y: (x, y - 1),
lambda x, y: (x, y + 1)
]
def maze_path(x1, y1, x2, y2): # 表示起点和终点的位置,x表示列,y表示行
stack = []
stack.append((x1, y1)) # 以元组的方式存入起始点
while len(stack) > 0: # 栈空表示没有路径, 假设存在路径
curNode = stack[-1] # 当前节点
if curNode[0] == x2 and curNode[1] == y2: # 判断当前点是否为终点
for p in stack:
print(p)
return True # 找到后返回True
# x,y 上下左右的四个方向为x+1, x-1, y+1, y-1
for dic in dirs:
nextNode = dic(curNode[0], curNode[1]) # 下一个节点的位置
if maze[nextNode[0]][nextNode[1]] == 0: # 下一个节点能走
stack.append(nextNode)
maze[nextNode[0]][nextNode[1]] = 2 # 将该点位置标记为2表示已经走过,
break # 遍历4个方向找是否能走的,找到一个就退出
else: # 如果没找到,先将走过的标记为2
maze[nextNode[0]][nextNode[1]] = 2
stack.pop()
else: # 没有找到
print("没有找到")
return False
maze_path(1,1,8,8)
路径不能保证是最短的,但是可以采用队列保证最短路径。
方法二:队列 - 广度优先搜索
- 思路:从一个节点开始,寻找所有接下来能继续走的点,继续不断寻找,直到找到出口。
- 使用队列存储当前正在考虑的节点
先找到出口的一定是最短的路程。
示例代码如下所示:
from collections import deque
maze = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 0, 0, 1, 0, 0, 0, 1, 0, 1],
[1, 0, 0, 1, 0, 0, 0, 1, 0, 1],
[1, 0, 0, 0, 0, 1, 1, 0, 0, 1],
[1, 0, 1, 1, 1, 0, 0, 0, 0, 1],
[1, 0, 0, 0, 1, 0, 0, 0, 0, 1],
[1, 0, 1, 0, 0, 0, 1, 0, 0, 1],
[1, 0, 1, 1, 1, 0, 1, 1, 0, 1],
[1, 1, 0, 0, 0, 0, 0, 0, 0, 1],
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
]
dirs = [ # 写一个方向
lambda x, y: (x + 1, y), # 上
lambda x, y: (x - 1, y), # 下
lambda x, y: (x, y - 1),
lambda x, y: (x, y + 1)
]
def print_r(path):
curNode = path[-1] # z 最后一个节点
realpath = []
while curNode[2] != -1:
realpath.append((curNode[0:2]))
curNode = path[curNode[2]]
realpath.append(curNode[0:2]) # 起点
realpath.reverse() # 将自己本身倒序返回自己
for node in realpath:
print(node)
def maze_path_queue(x1, y1, x2, y2):
queue = deque()
queue.append((x1, y1, -1)) # 起点从-1来
path = [] # 用于储存curNode的位置
while len(queue) > 0:
curNode = queue.popleft() # 使用队列将队首的节点;队首出队且将队首存起来
path.append(curNode)
if curNode[0] == x2 and curNode[1] == y2: # 找到终点
print_r(path) # 打印路径
return True
for dir in dirs:
nextNode = dir(curNode[0], curNode[1]) # 使用nextNode将下一个位置的坐标存起来
if maze[nextNode[0]][nextNode[1]] == 0: # 表示下一个坐标能走
queue.append((nextNode[0], nextNode[1], len(path) - 1)) # 后续点进队,记录那哪个节点由谁带来的;上一个位置的坐标就是path的最后一个元素的下标
maze[nextNode[0]][nextNode[1]] = 2 # 走过的点标记为2
else:
print("没有路")
return False
maze_path_queue(1, 1, 8, 8)