给定一个迷宫,用数组表示,其中0表示没有障碍,1表示有障碍,寻求一个从左上角到右下角的路径。node
maze = [[0, 1, 0, 0, 0], [0, 1, 0, 1, 0], [0, 0, 0, 0, 0], [0, 1, 1, 1, 0], [0, 0, 0, 1, 0]]
假如只是寻找是否是存在一个路径,这个时候能够使用递归的算法。
递归算法实际上是将全部的可能路径都试探一下,只要一条路径试探成功,那么就会返回True,当全部路径都不成功的时候返回False。python
def find_maze(maze, i, j, row, col): """ Args: maze: 迷宫(二维数组) i,j: 路径开始的坐标,为(0,0) row,col: 矩阵的长和宽,也是路径结束的坐标 Returns: boolean: 是否存在路径 """ if i < 0 or i >= row or j < 0 or j >= col or maze[i][j] != 0: return False maze[i][j] = 2 # 标记表示已经走过 if i == row-1 and j == col-1: return True # 已经成功到达 if (find_maze(maze, i - 1, j, row, col) or find_maze(maze, i + 1, j, row, col) or find_maze(maze, i, j + 1, row, col) or find_maze(maze, i, j - 1, row, col)): return True return False
能够使用深度优先搜索来寻找一条路径,这条路径并不必定是最短路径。它使用是一种回溯的方法,若是没有遇到障碍,那么就一直向前寻找,直到路走不通,那么回溯到刚开始进入这条路径的节点。算法
具体的作法是使用一个栈来保存第一个节点的信息,而后栈不为空的时候进入循环:不断的寻找能够行走的路径存入到栈当中,当发现没有可走的路径的时候出栈。最后若是到达目的节点,由于栈中前一个元素是后一个元素的前驱节点,因此栈中保存的内容就是一条路径。数组
def find_available_point(maze, i, j, row, col): """一旦发现一个当前能够到达的节点就返回""" if i+1 < row and maze[i+1][j] == 0: return [i+1, j] if i-1 >= 0 and maze[i-1][j] == 0: return [i-1, j] if j + 1 < col and maze[i][j+1] == 0: return [i, j+1] if j - 1 >= 0 and maze[i][j-1] == 0: return [i, j-1] return [-1, -1] def find_maze_use_stack_with_path(maze, i, j, row, col): """使用栈来进行回溯法,当栈不为空的时候进行循环 循环的内容是:将栈顶的元素弹出来,而后将全部可能的结果进入栈中 """ path = [[i,j]] maze[i][j] = 2 while path: i, j = path[-1] if i == row-1 and j == col - 1: return path available_point = find_available_point(maze, i, j, row, col) if available_point[0] != -1: maze[available_point[0]][available_point[1]] = 2 path.append(available_point) else: path.pop() return path
宽度优先搜索的策略是一步一步不断的向外扩展,而不是像深度优先搜索同样沿一条路径一直探寻,探寻不到的时候回溯。因此,若是宽度优先搜索到达终点,那么它所探寻的路径必定是最短的。app
宽度优先搜索须要结合队列来使用,它不像栈那样能够直接保存前驱节点的信息,因此还须要记录节点的前驱节点。这里使用一个和迷宫同样大的数组来保存前驱节点的信息,也能够使用字典来保存这一信息。code
from queue import Queue def find_all_available_point(maze, i, j, row, col): """找到当前节点能够一步到达的全部节点""" result = [] if i+1 < row and maze[i+1][j] == 0: result.append([i+1, j]) if i-1 >= 0 and maze[i-1][j] == 0: result.append([i-1, j]) if j + 1 < col and maze[i][j+1] == 0: result.append([i, j+1]) if j - 1 >= 0 and maze[i][j-1] == 0: result.append([i, j-1]) return result def get_path(pre_nodes, i, j): """根据前驱节点来获得最终的路径,i,j为终节点 初始节点的前驱节点为它自己,可做为递归结束的条件 """ path = [[i, j]] while pre_nodes[i][j] != [i, j]: i, j = pre_nodes[i][j] path.append([i,j]) return path def find_maze_use_queue_with_path(maze, i, j, row, col): q = Queue() pre_nodes = [[0 for x in range(col)] for x in range(row)] pre_nodes[i][j] = [i, j] maze[i][j] = 2 q.put([i, j]) while not q.empty(): i, j = q.get() if i == row-1 and j == col-1: path = get_path(pre_nodes, i, j) path = path[::-1] # 翻转一下 return path available_points = find_all_available_point(maze, i, j ,row, col) if available_points: for available_point in available_points: pre_nodes[available_point[0]][available_point[1]] = [i, j] # 记录前驱节点 maze[available_point[0]][available_point[1]] = 2 q.put(available_point) return [] if __name__ == '__main__': maze = [[0, 1, 0, 0, 0], [0, 1, 0, 1, 0], [0, 0, 0, 0, 0], [0, 1, 1, 1, 0], [0, 0, 0, 1, 0]] x = find_maze_use_queue_with_path(maze, 0 ,0 , 5, 5) print(x)