找到迷宫的最短或最长解决方案

Finding the shortest or longest solution to a maze

我正在处理一项任务,我已经解决了主要问题并正在研究扩展练习。目前给出了一张地图,迷宫的所有可能解决方案都在打印如下的网格上标识:

    1 1 3 1 0 2 
    3 3 3 3 1 3 
    3 3 1 3 3 3 
    3 3 3 1 3 0 
    3 1 3 1 3 1 
    3 1 3 3 3 0 

其中 0 是空的 spaces,1 是墙,2 是目标,3 是已访问的 space。扩展任务是在给定起点的情况下给出迷宫的最短可能解。如果起点是一堵墙,那么迷宫是没法解的。这也很好。它应该能够适用于任何给定的迷宫。

我真的不知道从哪里开始解决这个问题。一个想法是对所有路径求和并找到其中最小的路径,但我不确定如何实现它。

目前这是我的代码:

EMPTY = 0
WALL = 1
GOAL = 2
VISITED = 3


def solve(grid, x, y):
    if grid[x][y] == GOAL:
        show_grid(grid)
        return True
    elif grid[x][y] == WALL:
        return False
    elif grid[x][y] == VISITED:
        return False
    else:
       # mark as visited
       grid[x][y] = VISITED

       # explore neighbors clockwise starting by going up
       if      ((x < len(grid)-1  and solve(grid, x + 1, y))
             or (y > 0            and solve(grid, x, y-1))
             or (x > 0            and solve(grid, x-1, y))
             or (y < len(grid)-1  and solve(grid, x, y+1))):
           return True
       else:
           return False


def show_grid (grid):
    for i in range(len(grid), 0, -1):
        # print("i: ", i)
        for element in grid[i-1]:
            print (element, end=" ")
        print()


def main ():
    grid =    [[EMPTY, WALL, EMPTY, EMPTY, EMPTY, EMPTY],
               [EMPTY, WALL, EMPTY, WALL, EMPTY, WALL],
               [EMPTY, EMPTY, EMPTY, WALL, EMPTY, EMPTY],
               [EMPTY, EMPTY, WALL, EMPTY, EMPTY, EMPTY],
               [EMPTY, EMPTY, EMPTY, EMPTY, WALL, EMPTY],
               [WALL, WALL, EMPTY, WALL, EMPTY, GOAL]]

    solve(grid, 0, 0)

扩展要求打印最短路径的长度,其中遍历1个方格为1次移动。感谢任何对此问题的帮助。

您正在使用递归探索网格,其中基本情况是找到 GOALsolve 的每个实例仅 return 是一个布尔值,因此您丢失了信息 - 实例所采用的路径。

重构,以便函数 return 在可行的情况下提供网格位置,并且累积来自实例的 后代 的 return 值。

您的条件需要重新考虑,并且您要确保探索所有路径(上、下、左、右)。在条件 bool((0,0)) -> True.

中使用 a tuple is evaluated True 这一事实可能会有所帮助

最后你可以:

  • 累积所有成功的路径然后在过程完成时确定最小和最大长度或
  • 评估成功的路径长度正在处理并使用占位符(?)变量保持当前的最大值和最小值 - 此选项丢弃路径信息,但如果您不需要,那没关系。

我试图根据您当前的代码来制定它,因为我假设您了解您当前的流程是如何工作的,并且从那里开始可能更容易。

您还可以将网格视为图形,每个 都是一个节点,其周围的节点有边。您可以先将网格解析为图表,然后使用任意数量的定义明确的算法遍历图表并找到您的答案。对于树解决方案,根将是搜索的起点。我没有太多使用使用图表的经验,所以我觉得我无法对此给出详细的答案 - 也许有人会用更好的解释.

我同意@wwii 的回答,如果你正在探索所有的解决方案,只需 return 每条成功路径的长度,然后找到最短的路径。这可以通过以下更改来实现:

  1. 将您求解的函数更改为 return 路径,而不是 true 或 false。
  2. 在每个节点上而不是将 3 用于访问,您可以将从该节点到解决方案(或原点)的最小长度设置为 -1 用于墙和无法到达解决方案的节点。无法到达解决方案的节点本质上是墙。

例如,

GOAL = 'G'
WALL = 'W'
EMPTY = 'E'


def solve(grid, x, y):
    if grid[x][y] == WALL or grid[x][y].endswith(GOAL):
        return grid[x][y]

    candidates = []
    # explore neighbors clockwise starting by going down
    if x < len(grid)-1:
        candidates.append('d' + solve(grid, x + 1, y))
    if y > 0:
        candidates.append('l' + solve(grid, x, y - 1))
    if x > 0:
        candidates.append('u' + solve(grid, x - 1, y))
    if y < len(grid)-1:
        candidates.append('r' + solve(grid, x, y + 1))

    # get rid of none solutions from candidates
    candidates = [x for x in candidates if not x.endswith(GOAL)]
    if not candidates: # if no solution, it's essentially a wall
        grid[x][y] = 'W'
    else: 
        # getting shortest path
        grid[x][y] = sorted(candidates, key=lambda x: len(x))[0]

        # for longest path use code below instead of above
        # grid[x][y] = sorted(candidates, key=lambda x: len(x))[-1]
    return grid[x][y]

如果访问了一个节点并到达了目标,则该节点的值可能类似于 'drrurG'。这意味着最短路径是向下,向右*2,向上,向右,目标。方向约定向下意味着向下一行,即 x+1。

当然,您可能需要更改代码的其他部分才能使其正常工作。


深思

上面的代码遍历了所有可能的路径。但你可能不需要。可能有更快的方法到达最短路径,因为这个问题不像其他一般寻路问题那么复杂。

例如,绝对最短路径显然是从起点到终点的直线。先检查一下。如果那不是解决方案,则开始检查下一个最短路径。看看这些是否有效。如果没有,请继续前进,直到找到为止。