【问题标题】:A star algorithm: Distance heuristics一星算法:距离启发式
【发布时间】:2017-10-27 11:33:46
【问题描述】:

我正在使用此处所示的 A 星算法(取自 http://code.activestate.com/recipes/578919-python-a-pathfinding-with-binary-heap/),但有一个我不明白的问题。

这里给出的启发式是两点之间距离的平方。我发现如果我取它的平方根,我的结果会更准确,但是函数的运行时间会急剧增加(即它比以前经历了很多很多的循环)。

为什么启发式的变化会导致它更准确,运行时间更长?

# Author: Christian Careaga (christian.careaga7@gmail.com)
# A* Pathfinding in Python (2.7)
# Please give credit if used

import numpy
from heapq import *


def heuristic(a, b):
    return (b[0] - a[0]) ** 2 + (b[1] - a[1]) ** 2

def astar(array, start, goal):

    neighbors = [(0,1),(0,-1),(1,0),(-1,0),(1,1),(1,-1),(-1,1),(-1,-1)]

    close_set = set()
    came_from = {}
    gscore = {start:0}
    fscore = {start:heuristic(start, goal)}
    oheap = []

    heappush(oheap, (fscore[start], start))

    while oheap:

        current = heappop(oheap)[1]

        if current == goal:
            data = []
            while current in came_from:
                data.append(current)
                current = came_from[current]
            return data

        close_set.add(current)
        for i, j in neighbors:
            neighbor = current[0] + i, current[1] + j            
            tentative_g_score = gscore[current] + heuristic(current, neighbor)
            if 0 <= neighbor[0] < array.shape[0]:
                if 0 <= neighbor[1] < array.shape[1]:                
                    if array[neighbor[0]][neighbor[1]] == 1:
                        continue
                else:
                    # array bound y walls
                    continue
            else:
                # array bound x walls
                continue

            if neighbor in close_set and tentative_g_score >= gscore.get(neighbor, 0):
                continue

            if  tentative_g_score < gscore.get(neighbor, 0) or neighbor not in [i[1]for i in oheap]:
                came_from[neighbor] = current
                gscore[neighbor] = tentative_g_score
                fscore[neighbor] = tentative_g_score + heuristic(neighbor, goal)
                heappush(oheap, (fscore[neighbor], neighbor))

    return False

'''Here is an example of using my algo with a numpy array,
   astar(array, start, destination)
   astar function returns a list of points (shortest path)'''

nmap = numpy.array([
    [0,0,0,0,0,0,0,0,0,0,0,0,0,0],
    [1,1,1,1,1,1,1,1,1,1,1,1,0,1],
    [0,0,0,0,0,0,0,0,0,0,0,0,0,0],
    [1,0,1,1,1,1,1,1,1,1,1,1,1,1],
    [0,0,0,0,0,0,0,0,0,0,0,0,0,0],
    [1,1,1,1,1,1,1,1,1,1,1,1,0,1],
    [0,0,0,0,0,0,0,0,0,0,0,0,0,0],
    [1,0,1,1,1,1,1,1,1,1,1,1,1,1],
    [0,0,0,0,0,0,0,0,0,0,0,0,0,0],
    [1,1,1,1,1,1,1,1,1,1,1,1,0,1],
    [0,0,0,0,0,0,0,0,0,0,0,0,0,0]])

print astar(nmap, (0,0), (10,13))

【问题讨论】:

    标签: python algorithm a-star


    【解决方案1】:

    为什么启发式的变化会导致它更准确,运行时间更长?

    第一个启发式,距离平方,高估了实际距离(很多,取决于情况),即使实际距离的计算方式相同,因为实际距离计算为单个步骤的总和(总和的平方小于和的平方)。 A* 倾向于通过没有足够的探索来保证找到最佳路线来对此做出回应,它更喜欢继续沿着它正在尝试的任何路线走,因为离目标更近一步会减少到目标的预期距离很多 (远远超过步骤本身,因为启发式高估了太多)。它通常不会备份(即从队列中取出一些先前打开的节点而不是最近的节点)并尝试其他操作,因为返回意味着 H 值上升超过 G 值下降。

    所以这有你看到的两个效果:

    1. 它通常要快得多(除了在某些迷宫中,您可以“诱骗”算法走错路的时间比其他情况要长)
    2. 不一定能找到最佳路线

    您的连通性是 8 邻域,对此有比欧几里得距离更好的启发式方法。请注意,路径不能有任意角度,它必须直行或呈 45 度角,因此即使没有障碍物,欧几里德距离也会低估距离。这对于正确性来说是可以的,但是您可以使用“对角距离”启发式:(取自 here 并且易于适应 Python - 该网站还讨论了高估启发式的影响)

    function heuristic(node) =
        dx = abs(node.x - goal.x)
        dy = abs(node.y - goal.y)
        return D * (dx + dy) + (D2 - 2 * D) * min(dx, dy)
    

    您将拥有D = 1, D2 = sqrt(2) 来匹配您的欧几里得距离度量。


    如果多条路径共享一个源或目标,则可以使用一些技术来重用某些工作(不管是哪一个,因为它是对称的)。例如,当您从 A 搜索到 B 时,G 分数可以存储在网格中(它们甚至可以被排除在节点之外)。然后在搜索 A 的路径时,那些保存的 G 分数代表到 A 的实际距离。显然,这些可以用来获得完美的启发式算法,但还有更快的用法:如果从队列中抽取一个使用如此完美的启发式计算其 F 的节点,那么最短路径是肯定通过该节点(因为它的 F 是 实际路径,并且显然是从优先级队列中出来后最短的路径),此外,您无需进一步搜索即可知道路径(贪婪地按照保存的 G 分数返回 A)。

    这导致每次搜索路径都会建立可用于另一个方向的其他搜索的信息。然后在另一个方向上的搜索再次为 另一个方向上的搜索建立信息,依此类推。应该注意一些 - 很容易让内存使用爆炸。可能并非所有信息都可以保留。

    这可能也可以与跳跃点搜索结合使用,尽管要保存的 G 会更少,所以它可能不是很有效,主要是浪费大量空间。

    【讨论】:

    • 谢谢!在我的情况下,没有找到绝对最佳的路线很好。我尝试使用启发式函数,但即使这些点彼此相当接近,它也需要很长时间(我有几万条路径要找到)。问题是,使用当前的(平方)启发式方法,我会进入大量路线的那些“迷宫”。您对如何在不使用您提供的启发式方法的情况下为 那些 路线找到近似最短路径有什么建议吗?
    • @johannes 如果它在您的地图上有意义,您可以尝试跳转点搜索(这在相对开放的区域有很大帮助),或者缩放启发式我放弃了一点以使其“减少探索” -prone”(也许两者都有?)。还有什么是路径的性质?例如,如果有很多通往或离开同一点的路径,则可以重用大量计算。
    • 是的,应该可以的。我正在尝试沿着海岸线在海上的一组位置之间找到路径。所以有时它们之间会有很少或没有物体。从每一点我都试图找到大约的路径。 10-100 其他点。
    • @johannes 那么你想要所有这些路径还是最短的路径?两者都有捷径,但只有最短的路径有更短的捷径
    • 我想要所有的路径。
    猜你喜欢
    • 2014-06-05
    • 2015-01-30
    • 2019-04-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2017-11-15
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多