如果原始算法是BFS,则您正在寻找最短路径中的最小路径,其中“最小”是根据边缘上的某个总序列
Ord
引起的词典顺序(当然,“最短”是按照路径长度)。调整权重的想法是自然的,但我认为这不是很实用,因为权重需要具有与路径长度可比的位数,以避免丢弃信息,这将使算法变得慢得多。幸运的是,这仍然可以通过对A*进行两个简单而廉价的修改来完成:
1.一旦到达目标,我们应该继续访问节点,直到路径长度增加,这样我们就可以访问所有属于最短路径的节点。
2.在重建路径时,我们构建贡献于最短路径的节点集。当考虑所有最短路径边缘时,此集合具有DAG结构,现在可以在此DAG中找到从
start
到
goal
的字典顺序最小路径,这是所需的解决方案。
经典A*的示意图如下:
path_length = infinity for every node
path_length[start] = 0
while score(goal) > minimal score of unvisited nodes:
x := any unvisited node with minimal score
mark x as visited
for y in unvisited neighbors of x:
path_length_through_x = path_length[x] + d(x,y)
if path_length[y] > path_length_through_x:
path_length[y] = path_length_through_x
ancestor[y] = x
return [..., ancestor[ancestor[goal]], ancestor[goal], goal]
这里的score(x)
表示path_length[x] + heuristic(x, goal)
。
我们只需将严格的while
循环不等式变为非严格的,并添加路径重构阶段:
path_length = infinity for every node
path_length[start] = 0
while score(goal) >= minimal score of unvisited nodes:
x := any unvisited node with minimal score
mark x as visited
for y in unvisited neighbors of x:
path_length_through_x = path_length[x] + d(x,y)
if path_length[y] > path_length_through_x:
path_length[y] = path_length_through_x
optimal_nodes = [goal]
for every x in optimal_nodes: // note: we dynamically add nodes in the loop
for y in neighbors of x not in optimal_nodes:
if path_length[x] == path_length[y] + d(x,y):
add y to optimal_nodes
path = [start]
x = start
while x != goal:
z = undefined
for y in neighbors of x that are in optimal_nodes:
if path_length[y] == path_length[x] + d(x,y):
z = y if (x,y) is smaller than (x,z) according to Ord
x = z
append x to path
return path
警告:引用Knuth的话,我只证明了它的正确性,而没有尝试过。
至于性能影响,应该是很小的:搜索循环仅访问得分比经典A*高1个单位的节点,并且重构阶段在属于最短路径的节点数几乎线性。如果像你所暗示的那样,在大多数情况下只有一条最短路径,则影响更小。甚至可以针对这种特殊情况进行优化,例如通过记住一个祖先节点(如经典情况),当存在多个祖先时(即当path_length[y] == path_length_through_x
时)将其设置为特殊错误值。一旦搜索循环结束,您尝试通过ancestor
检索路径,就像经典A*一样;仅在构建路径时遇到错误值时才需要执行完整的路径重构。
h(v)在[0,1]
范围内,A将会像BFS一样运行,除了最后一步... - amitw(u,v) = 1 + f(u)*prio(u,v)
,其中:(1) 所有边的加权总和不超过1。(2)f(u)
是基于源点到目标点的距离(可能是启发式的?)计算出来的,并且单调递减,这样每个 f(u) 都比在最短路径中跟随它的所有节点“更重要”[可能具有 Zeno 性质并呈指数衰减]。然而,我无法想出一种证明它有效的方法,并且还怀疑它可能会漏掉一些细节。 - amit