Dijkstra's Algorithm
Shortest distance from a source to every vertex, with non-negative edge weights.
Open on GeeksforGeeks ↗Intuition
Repeatedly finalise the nearest vertex that is not yet settled. This works precisely because weights are non-negative: any other route to that vertex would have to pass through something even further away, which can only add cost. So the closest unsettled vertex can never improve later — settle it and relax its edges.
Shortest paths with non-negative weights. A plain BFS queue fails once edges carry different costs, so the queue becomes a priority queue ordered by distance — that's the entire modification. The greedy is safe only because weights are non-negative: a settled vertex can never be improved by a longer detour. Negative edges break that and require Bellman-Ford.
Approach
Greedy settle order
Keep tentative dist[], all ∞ except the source. Pick the smallest unsettled distance, mark it settled, and relax its outgoing edges: dist[v] = min(dist[v], dist[u] + w).
Use a heap
Scanning for the minimum is O(V) per step, giving O(V²). A binary heap makes it O(log V), for O((V + E) log V) overall — push improved distances and skip stale heap entries.
Why negative weights break it
A negative edge could make a far-away route cheaper after a vertex was settled, violating the settle-once guarantee. Use Bellman–Ford in that case.
Solution & live demo
Common pitfalls
Not skipping stale heap entries
d, u = heapq.heappop(pq) for v, w in adj[u]: ...
d, u = heapq.heappop(pq)
if d > dist[u]:
continueVertices are pushed again whenever a shorter route is found, so the heap accumulates outdated pairs. Processing one re-expands a vertex using a distance already beaten — correct answers, but wasted work that can dominate the runtime on dense graphs.
Marking vertices visited instead of comparing distances
if seen[u]: continue seen[u] = True
if d > dist[u]: continue
A visited flag works here, but comparing against dist[u] is strictly more informative and is what generalises to variants that revisit vertices. It also needs no extra array.
Pushing without relaxing first
for v, w in adj[u]:
heapq.heappush(pq, (d + w, v))if d + w < dist[v]:
dist[v] = d + w
heapq.heappush(pq, (dist[v], v))Pushing every edge unconditionally makes the heap grow to O(E) with entries that will never improve anything. Only a genuine improvement deserves a push.
Edge cases
Distance stays ∞.
Pop and skip any entry whose distance exceeds the recorded dist[u].
Fine — only strictly negative weights break the argument.