我的递归寻路函数中的哪些算法冗余导致了本质上无限的运行时间?

What algorithmic redundancies in my recursive pathfinding function are causing essentially infinite runtime?

通常当出现这种问题时,答案是某种无限循环。但是我无法确定在我的代码中可以引入的位置。

假设我们正在处理一个标准的 8x8 棋盘,我想找到从一个方格到另一个方格的最有效路径,比如从红色到绿色。解决方案是3步。

def calculate_dest(curr, path):
    return (curr[0] + path[0], curr[1] + path[1])

def curr_is_valid(curr):
    return 0 <= curr[0] <= 7 and 0 <= curr[1] <= 7

def helper(dest, soFar):
    # if len(soFar) > 4:
    #     return 63
    if not curr_is_valid(soFar[-1]):
        return 63
    elif soFar[-1] in soFar[:-1]:
        return 63
    elif soFar[-1] == dest:
        return len(soFar) - 1
    else:
        return min(helper(dest, soFar + [calculate_dest(soFar[-1], p)]) for p in [(2, 1),
                                                                                  (2, -1),
                                                                                  (-2, 1),
                                                                                  (-2, -1),
                                                                                  (1, 2),
                                                                                  (1, -2),
                                                                                  (-1, -2),
                                                                                  (-1, 2)])

dest:目标点表示为元组(即(0, 1)

soFar:记录遍历的所有点,表示为元组列表(即[(0, 1), (1, 3)]

当我 运行 上面的代码 注释未注释时 , helper((0, 1), [(0, 0)]) returns 3 就像我在 2 中期望的那样秒。不太好,但是当我把评论放回去时,因为该功能应该适用于棋盘上的任意数量的移动,它保持 运行ning,基本上永远(我试着等了几分钟,但那时你知道出事了)。

我很确定基本情况 soFar[-1] in soFar[:-1] 应该处理开始重新交叉的路径,这肯定会引入无限循环,所以我不确定为什么函数 运行进入无限循环?

也有可能是我设计函数的方式从根本上来说效率低下。我的想法是在这种情况下递归是必要的。

您想做一个 BFS 因为它保证 return 最短路径。

代码如下:

def is_valid(curr):
    return 0 <= curr[0] <= 7 and 0 <= curr[1] <= 7

def get_neighbors(cur):
    for offset in [(2, 1),
                    (2, -1),
                    (-2, 1),
                    (-2, -1),
                    (1, 2),
                    (1, -2),
                    (-1, -2),
                    (-1, 2)]:
        nxt = (cur[0] + offset[0], cur[1] + offset[1])
        if is_valid(nxt):
            yield nxt

def helper(start, dest):
    visited = set()
    q = [(start, 0)]
    while q:
        front, distance = q.pop(0)
        visited.add(front)
        if front == dest:
            return distance
        for neighbor in get_neighbors(front):
            if neighbor not in visited:
                q.append((neighbor, distance + 1))
print(helper((0, 0), (0, 1)))

输出:

3