Dijkstra的算法:我的实现有缺陷吗?

时间:2016-08-11 14:00:00

标签: algorithm python-3.x graph dijkstra

为了在Python和图论中训练自己,我尝试使用Python 3实现Dijkstra算法,并将其提交给几位在线评委,以确定它是否正确。

在许多情况下效果很好,但并非总是如此。

例如,我坚持使用this one:测试用例工作正常,我也尝试了自己的自定义测试用例,但是当我提交以下解决方案时,法官一直告诉我“错误答案”确实,预期结果与我的输出非常不同。

请注意,法官会对相当复杂的图形(10000个节点,边缘为100000)进行测试,而我之前尝试的所有情况都不会超过20个节点和大约20-40个边缘。

这是我的代码。

给出al以下形式的邻接表:

al[n] = [(a1, w1), (a2, w2), ...]

,其中

  • n是节点ID;
  • a1, a2, etc.是其相邻节点,w1, w2, etc.是给定边缘的相应权重;

假设最大距离不超过10亿,我用这种方式实现了Dijkstra的算法:

import queue

distance = [1000000000] * (N+1) # this is the array where I store the shortest path between 1 and each other node
distance[1] = 0 # starting from node 1 with distance 0

pq = queue.PriorityQueue()
pq.put((0, 1)) # same as above

visited = [False] * (N+1) 

while not pq.empty():
    n = pq.get()[1]
    if visited[n]:
        continue
    visited[n] = True
    for edge in al[n]:
        if distance[edge[0]] > distance[n] + edge[1]:
            distance[edge[0]] = distance[n] + edge[1]
            pq.put((distance[edge[0]], edge[0]))

你能不能帮我理解我的实施是否有缺陷,或者我是否只是遇到了一些错误的在线评判?

非常感谢。

更新

根据要求,我提供了用于填充关联问题的邻接列表al的代码段。

N,M = input().split()
N,M = int(N), int(M)

al = [[] for n in range(N+1)]

for m in range(M):
    try:
        a,b,w = input().split()
        a,b,w = int(a), int(b), int(w)
        al[a].append((b, w))
        al[b].append((a, w))
    except:
       pass

(请不要介意丑陋的“除了:传递”,我只是出于调试目的使用它......:P)

1 个答案:

答案 0 :(得分:1)

解释问题的主要问题:

根据您的解析代码,您将输入数据视为无向图,即A到B的每条边也是从B到A的边。 看起来这个前提是无效的,它应该是一个定向的图,即你必须删除这一行:

    al[b].append((a, w))  # no back reference!

以前的问题,现在已在代码中修复:

目前,您正在使用队列边缘永不变化的权重:

        pq.put((edge[1], edge[0]))

这样,无论算法的哪个阶段以及到达该节点的路径到底有多远,节点总是最终位于队列中的相同位置。 相反,您应该使用到目标节点edge[0]的新距离,即distance[edge[0]]作为队列中的优先级:

        pq.put((distance[edge[0]], edge[0]))