python-使用Dijkstra的算法时是否必须检查一次以上的访问节点?
作者:互联网
我和我的同事正在讨论Dijkstra算法的实现.这是使用Python的实现:
def dijkstra(self, origin, destination):
"""Use Dijkstra's algorithm to find the cheapest path."""
routes = Heap()
for neighbor in self.neighbors(origin):
price = self.get_price(origin, neighbor)
routes.push(Route(price=price, path=[origin, neighbor]))
visited = set()
visited.add(origin)
while routes:
# Find the nearest yet-to-visit airport
price, path = routes.pop()
airport = path[-1]
if airport in visited:
continue
# We have arrived! Wo-hoo!
if airport is destination:
return price, path
# Tentative distances to all the unvisited neighbors
for neighbor in self.neighbors(airport):
if neighbor not in visited:
# Total spent so far plus the price of getting there
new_price = price + self.get_price(airport, neighbor)
new_path = path + [neighbor]
routes.push(Route(new_price, new_path))
visited.add(airport)
return float('infinity')
有争议的行是:
if neighbor not in visited:
我的观点是,此行必须替换为
if neighbor not in visited or new_price < cost_so_far[neighbor]
在我发现的所有算法实现中,您必须检查到达成本低于当前节点成本的节点时的情况.例如,此伪代码从Wikipedia开始的第17和18行:
1 function Dijkstra(Graph, source):
2 dist[source] ← 0 // Initialization
3
4 create vertex set Q
5
6 for each vertex v in Graph:
7 if v ≠ source
8 dist[v] ← INFINITY // Unknown distance from source to v
9 prev[v] ← UNDEFINED // Predecessor of v
10
11 Q.add_with_priority(v, dist[v])
12
13
14 while Q is not empty: // The main loop
15 u ← Q.extract_min() // Remove and return best vertex
16 for each neighbor v of u: // only v that is still in Q
17 alt = dist[u] + length(u, v)
18 if alt < dist[v]
19 dist[v] ← alt
20 prev[v] ← u
21 Q.decrease_priority(v, alt)
22
23 return dist[], prev[]
问题是:我的同事的实施是否正确,还是应该修改代码以检查您是否到达某个价格低于当前价格的邻居?
注意:这是我同事的实施方案的source code.
解决方法:
所以,问题是代码中的行是否
if neighbor not in visited:
可以或必须替换为
if neighbor not in visited or new_price < cost_so_far[neighbor]:
答案是:可以,可以;可以.必须,不.
添加new_price< cost_so_far [neighbor]不会改变算法流程中的任何内容,每次未访问的邻居为false时为false.
原因是Dijkstra的算法如何工作.
本质上,它构建了最短路径的树.
每当添加一个要访问的机场时,都将其视为在树中:到此时,该算法已经找到到达该机场的最短路径.
假设在步骤x,我们向访问的机场添加了一个特定的机场A.
进一步假设在步骤y> x,到机场A的cost_so_far减少了.
怎么减少呢?
它将要求new_price = price self.get_price(机场,邻居)的价格小于步骤y的价格.
现在回想一下,路由是一个优先队列,因此它以非降序提供价格.
图的边缘也是非负的(否则,Dijkstra的算法确实会产生错误的结果,因此不适用).
因此,我们产生了一个矛盾:新的new_price至少是旧价格,但事实证明比旧价格要低.
造成混淆的原因可能是,实现的主循环一对一地考虑某些路由.
本质上,这些路线与图形的边缘相对应.
因此,可以有| E |路线,但只有| V |他们中的一个将被接受,如果访问过机场,则所有其他条件将失败:继续.
如果我们实现该算法,以便主循环的每次迭代恰好增加了一个要访问的机场(恰好是最短路径树的一个顶点),则整个问题可能会变得更加清晰.
标签:dijkstra,shortest-path,python,algorithm 来源: https://codeday.me/bug/20191119/2033884.html