Дейкстра на графе с одним отрицательным ребром
Граф из четырёх вершин: A -> B вес 1, A -> C вес 2, C -> B вес -2, B -> D вес 1. Отрицательных циклов нет.
import heapq
def dijkstra(graph, start):
dist = {v: float('inf') for v in graph}
dist[start] = 0
done = set()
pq = [(0, start)]
while pq:
d, u = heapq.heappop(pq)
if u in done:
continue
done.add(u)
for v, w in graph[u]:
if d + w < dist[v]:
dist[v] = d + w
heapq.heappush(pq, (dist[v], v))
return dist
Алгоритм возвращает dist['D'] == 2, хотя настоящий кратчайший путь A -> C -> B -> D стоит 1. Почему?
- Проблема в heapq: при отрицательных ключах куча не гарантирует правильный порядок извлечения
- Извлечённая вершина считается окончательной, а отрицательное ребро улучшает её уже после закрытия
- Достаточно прибавить ко всем весам константу и убрать отрицательные: кратчайший путь от сдвига не меняется
- Дейкстра ломается только на отрицательном цикле, а отдельное отрицательное ребро обрабатывает корректно
