← Back to Algorithm series
πŸ›£οΈ
Graphs (Advanced)
Priority queue Β· no negative weights

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.

Dijkstrashortest pathheapq
Duration
⏱ ~1 hour
Level
πŸ“Š Advanced
Prerequisite
🎯 BFS + heap
OUTCOME
Write Dijkstra in 15 lines and apply it to weighted shortest path problems.

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

  1. Initialize dist[start] = 0, all others = infinity.
  2. Push (0, start) into a min-heap.
  3. Pop the closest node; if its distance is stale (greater than dist[u]), skip.
  4. For each neighbor v with edge weight w, if dist[u] + w < dist[v], update and push.
  5. Repeat until the heap is empty.

2. Standard implementation

python
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 dist

3. 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

python
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

  1. Running Dijkstra on a graph with negative weights β€” silent wrong answers.
  2. Pushing (node, dist) instead of (dist, node) β€” heap sorts by first element!
  3. Forgetting the stale-entry check β†’ can explode to O(VE log V).
  4. 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

  1. BOJ 1753 (Shortest path).
  2. BOJ 1916 (Minimum cost).
  3. BOJ 1238 (Party).
Example code / lecture materials

All lecture materials and example code are openly available on GitHub.

View on GitHub β†—