迷宫寻路实现BFS没有给出正确的路径

问题描述

我正在尝试为带球的迷宫获得最短路径:球一直滚动直到撞到墙壁。我使用 Dijkstra 算法将 heapq 用于优先队列。但是,我得到了一条非最佳路径。

这是我的示例输入代码

maze = [[0,1,0],[0,[1,1],0]]

start = (0,0)
end = (22,22)

def shortestdistance(maze: List[List[int]],start: List[int],destination: List[int]):
    start,destination = tuple(start),tuple(destination)
    row,col = len(maze),len(maze[0])
    moves = [(-1,0),(0,1),-1),(1,0)]
    dstr = ['u','r','l','d']

    class Point:
        def __init__(self,distance,coordinates,directions):
            self.distance = distance
            self.coordinates = coordinates
            self.directions = directions

        def __eq__(self,p):
            if self.distance == p.distance:
                return self.__lt__(self,p)

            return self.distance - p.distance

        def __lt__(self,p):
            return len(self.directions) - len(p.directions)


    heap = [(Point(0,start,""))]
    visited = set()
    while heap:
        point = heapq.heappop(heap)
        dist = point.distance
        node = point.coordinates
        directions = point.directions

        if node in visited: continue
        if node == destination:
            return directions

        visited.add(node)

        for idx,move in enumerate(moves):
            dx,dy = move
            newX = node[0]
            newY = node[1]
            distance = dist
            newDirections = directions
            while 0 <= newX + dx < row and 0 <= newY + dy < col and maze[newX + dx][newY + dy] == 0:
                newX += dx
                newY += dy
                distance += 1
                if (newX,newY) == destination:
                    break

            if (newX,newY) not in visited:
                heapq.heappush(heap,Point(distance,(newX,newY),newDirections + dstr[idx]))

    return "Impossible"


path = shortestdistance(maze,end)
print(path)

这个想法是比较距离,如果相等,选择方向变化较少的路径。

我目前正在获取 rdrludlrdrudludldldr(即右下右左...)作为输出,但在索引 2 处找到的序列“rl”没有意义:“Right”应该后面不能跟“左”,也不应该跟“上”跟“下”,反之亦然。这样的顺序显然不是最佳的,因为可以省略这两个移动中的第一个,以使球在同一位置并移动更短的距离。

这个迷宫的预期输出drururdrdrurdrd

为什么我没有得到最短路径?

解决方法

问题在于 __lt__ 函数没有做它应该做的事情。

它应该返回一个布尔值,当 self 被认为小于 p 时为真。当您当前返回一个整数结果时,该结果通常是非零的,您会遇到这样的情况:一对 (p,q) 点将 p

以下是您如何定义它:

def __lt__(self,p):
    return ((self.distance,len(self.directions),self.directions) < 
          < (p.distance,len(p.directions),p.directions)) 

通过此更改返回的路径是

rdrdldldrdr

简化

您可以使用命名元组,而不是创建类 Point,这使一切变得更容易(更快)。您只需要更改“属性”的顺序,以便这些点以所需的方式进行比较,即 directions 应该在 coordinates 之前,方向字符串的长度应该有自己的属性:

from collections import namedtuple

# change order of properties so comparison works as intended
Point = namedtuple("Point","distance,length,directions,coordinates")

然后在调用 Point 的地方进行适当的更改:

heap = [Point(0,"",start)]
# ...
heapq.heappush(heap,Point(distance,len(newDirections) + 1,newDirections + dstr[idx],(newX,newY)))