保持 BFS 搜索的路径

Keeping the path of BFS search

给定一个迷宫、起点坐标和终点坐标,

maze = [
    [BLACK, BLACK, WHITE, WHITE],
    [BLACK, WHITE, WHITE, WHITE],
    [WHITE, WHITE, BLACK, WHITE],
    [WHITE, WHITE, BLACK, WHITE],
]
s = Coordinate(3, 0)
e = Coordinate(0, 3)

我正在尝试使用 BFS 查找从头到尾的路径。 找到路径很简单,但我正在努力保持通往目的地的路径。 我试过的是

directions = [(1, 0), (0, 1), (-1, 0), (0, -1)]
queue = collections.deque()
queue.append(s)
path = []
while queue:
    curr = queue.popleft()
    if curr == e:
        path.append(curr)
        return path
    path.append(curr)
    maze[curr.x][curr.y] = BLACK
    for x, y in directions:
        new_x, new_y = curr.x + x, curr.y + y
        if new_x < 0 or new_y < 0 or new_x >= len(maze) or new_y >= len(maze[0]) or maze[new_x][new_y] == BLACK:
            continue
        queue.append(Coordinate(new_x, new_y))

类似这样,但结果打印出我访问过的所有节点,而不是最终路径。关于保持正确路径和删除不属于最终路径的节点有什么技巧吗?

for x, y in directions:
    new_x, new_y = curr.x + x, curr.y + y
    if new_x < 0 or new_y < 0 or new_x >= len(maze) or new_y >= len(maze[0]) or maze[new_x][new_y] == BLACK:
        continue
    queue.append(Coordinate(new_x, new_y))

你的 queue.append(Coordinate(new_x, new_y)) 是 运行 每次你的 for 循环迭代。

我们希望这个条件只在我们的 if 条件运行时发生,所以让我们尝试这样的事情:

for x, y in directions:
    new_x, new_y = curr.x + x, curr.y + y
    if new_x < 0 or new_y < 0 or new_x >= len(maze) or new_y >= len(maze[0]) or maze[new_x][new_y] == BLACK:
        queue.append(Coordinate(new_x, new_y))
        continue

当满足我们的 if 条件时,附加它,然后继续。让我知道这是否有帮助。

您可以维护一个 edge_to 字典,而不是维护一个 path 列表,该字典跟踪哪个先前的顶点导致访问某个顶点。每当您向队列中添加内容时,您都可以更新 edge_to。使用此方法修改后的函数版本如下:

Coordinate = collections.namedtuple('Coordinate', ['x', 'y'])

def find_path(s, e):
    directions = [(1, 0), (0, 1), (-1, 0), (0, -1)]
    queue = collections.deque()
    queue.append(s)
    edge_to = {s: None}

    while queue:
        curr = queue.popleft()
        if curr == e:
            return path(edge_to, curr)
        maze[curr.x][curr.y] = BLACK
        for x, y in directions:
            new_x, new_y = curr.x + x, curr.y + y
            if new_x < 0 or new_y < 0 or new_x >= len(maze) or new_y >= len(maze[0]) or maze[new_x][new_y] == BLACK:
                continue
            c = Coordinate(new_x, new_y)
            edge_to[c] = curr
            queue.append(c)

当您找到结束顶点时,请注意对 path(...) 的调用。该函数只是从 edge_to 字典中构建一个列表:

def path(edge_to, end):
    curr = end
    res = []
    while curr != None:
        res.append(curr)
        curr = edge_to[curr]
    return list(reversed(res))

对于给定的迷宫、起点和终点坐标,我们得到以下输出:

s = Coordinate(3, 0)
e = Coordinate(0, 3)
print(find_path(s, e))

输出

[Coordinate(x=3, y=0), Coordinate(x=2, y=0), Coordinate(x=2, y=1), Coordinate(x=1, y=1), Coordinate(x=1, y=2), Coordinate(x=0, y=2), Coordinate(x=0, y=3)]