• 迷宫问题


    问题描述

    给定一个迷宫,用数组表示,其中0表示没有障碍,1表示有障碍,寻求一个从左上角到右下角的路径。

    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。

    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
    

    使用深度优先搜索(DFS)寻找一条路径

    可以使用深度优先搜索来寻找一条路径,这条路径并不一定是最短路径。它使用是一种回溯的方法,如果没有遇到障碍,那么就一直向前寻找,直到路走不通,那么回溯到刚开始进入这条路径的节点。

    具体的做法是使用一个栈来保存第一个节点的信息,然后栈不为空的时候进入循环:不断的寻找可以行走的路径存入到栈当中,当发现没有可走的路径的时候出栈。最后如果到达目的节点,因为栈中前一个元素是后一个元素的前驱节点,所以栈中保存的内容就是一条路径。

    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
    

    使用宽度优先搜索(BFS)得到最短的路径

    宽度优先搜索的策略是一步一步不断的向外扩展,而不是像深度优先搜索一样沿一条路径一直探寻,探寻不到的时候回溯。所以,如果宽度优先搜索到达终点,那么它所探寻的路径一定是最短的。

    宽度优先搜索需要结合队列来使用,它不像栈那样可以直接保存前驱节点的信息,所以还需要记录节点的前驱节点。这里使用一个和迷宫一样大的数组来保存前驱节点的信息,也可以使用字典来保存这一信息。

    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)
    
  • 相关阅读:
    面对满足正态分布的事情,我们如何增加成功概率
    《灭火:美国金融危机及其教训》笔记
    《失控:机器、社会与经济的新生物学》笔记
    外推谬误
    迎接未来,我们可以做什么
    怎样理解帝国与王朝的兴衰,以及它对组织管理有何启示?
    vue中$emit的用法,父子组件传值及页面跳转之间传值
    SharePoint Online 调用PnP.js 搜索返回结果不完整
    SharePoint REST API 的 Expand 方法
    SharePoint Online PnPjs 批量更新项目
  • 原文地址:https://www.cnblogs.com/jiaxin359/p/9520682.html
Copyright © 2020-2023  润新知