24. Dijkstra's Algorithm
Single-source shortest path in a graph with non-negative weights. The heapq-based implementation is the de facto standard for competitive programming.
What you'll learn
- 1Implement Dijkstra with a heap
- 2Skip stale entries with the standard distance-check
- 3Recover the actual path with a parent array
Overview
Dijkstra greedily expands the closest unvisited node. With a binary heap, it runs in O((V + E) log V). It fails on negative weights β use Bellman-Ford or SPFA for those.
Core Concepts
1. Algorithm
- Initialize dist[start] = 0, all others = infinity.
- Push (0, start) into a min-heap.
- Pop the closest node; if its distance is stale (greater than dist[u]), skip.
- For each neighbor v with edge weight w, if dist[u] + w < dist[v], update and push.
- Repeat until the heap is empty.
2. Standard implementation
import heapq
def dijkstra(start, adj, n):
INF = float('inf')
dist = [INF] * (n + 1)
dist[start] = 0
heap = [(0, start)]
while heap:
d, u = heapq.heappop(heap)
if d > dist[u]:
continue # stale entry
for v, w in adj[u]:
nd = d + w
if nd < dist[v]:
dist[v] = nd
heapq.heappush(heap, (nd, v))
return dist3. Why we don't need a visited array
The `if d > dist[u]: continue` check skips stale entries that were pushed when a shorter path hadn't been found yet. This is cleaner than maintaining a separate visited set.
4. Reconstructing the path
parent = [-1] * (n + 1)
# ... in the relaxation step ...
if nd < dist[v]:
dist[v] = nd
parent[v] = u
heapq.heappush(heap, (nd, v))
def reconstruct(target):
path = []
cur = target
while cur != -1:
path.append(cur)
cur = parent[cur]
return path[::-1]5. When NOT to use Dijkstra
- Negative edges β Bellman-Ford or SPFA
- Negative cycles β no shortest path exists
- All edges weight 1 β use BFS (simpler)
- Dense graphs with VΒ² edges β may be faster with adjacency matrix + O(VΒ²)
Examples
Example 1 β src/01_dijkstra.py
Standard Dijkstra returning a dist array.
Example 2 β src/02_dijkstra_path.py
Dijkstra with path reconstruction.
Example 3 β src/03_dijkstra_grid.py
Dijkstra on a 2D grid where moving has variable cost.
Example 4 β src/04_dijkstra_compare.py
Compare BFS vs Dijkstra: same answer on unweighted, BFS is faster.
Common Mistakes
- Running Dijkstra on a graph with negative weights β silent wrong answers.
- Pushing (node, dist) instead of (dist, node) β heap sorts by first element!
- Forgetting the stale-entry check β can explode to O(VE log V).
- Using sys.maxsize and getting overflow in dense graphs β use float('inf').
Recap
- Dijkstra: heap + dist array + stale check.
- O((V + E) log V) with binary heap.
- No negative weights.
Try It
- BOJ 1753 (Shortest path).
- BOJ 1916 (Minimum cost).
- BOJ 1238 (Party).
All lecture materials and example code are openly available on GitHub.
View on GitHub β