AI InterviewSearch…Search problems, topics, or pages…Ctrl KGet started
Skip to content

08 Shortest paths: BFS, 0-1 BFS, Dijkstra / Lesson 1 of 1

Shortest paths — BFS, 0-1 BFS and Dijkstra

16 min · +10 XP · 2 exercises · 4 questions

Read the text16 min
Exercises0/2
Quiz4 q

Quick answer

How do you implement Dijkstra's algorithm in C++?

Dijkstra's algorithm finds shortest distances from one source when every edge weight is non-negative. In C++ keep a dist array at infinity, push {0, source} into a priority_queue ordered smallest first, and repeatedly pop the closest pair: skip it if its distance is stale, otherwise relax each out-edge and push any improved neighbour. It runs in O((V + E) log V).

Pick the algorithm from the edge weights, never from habit:

WeightsAlgorithmCost
all equal (grid moves)BFS, queueO(V + E)
only 0 or 10-1 BFS, dequeO(V + E)
non-negativeDijkstra, priority_queueO((V + E) log V)
some negativeBellman–FordO(V · E)

BFS and 0-1 BFS

  • BFS pops vertices in order of edge count; set dist[v] when v is first pushed, and a cell is never queued twice.
  • 0-1 BFS: a 0-edge push_fronts the neighbour, a 1-edge push_backs it. The deque holds at most two distance values, in order, so its front is always a closest vertex.
deque<int> dq{src};
dist[src] = 0;
while (!dq.empty()) {
    int u = dq.front(); dq.pop_front();
    for (auto [v, w] : adj[u])
        if (dist[u] + w < dist[v]) {
            dist[v] = dist[u] + w;
            w == 0 ? dq.push_front(v) : dq.push_back(v);
        }
}

Dijkstra, the contest way

vector<ll> dist(n + 1, LLONG_MAX);
priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<>> pq;
dist[src] = 0;
pq.push({0, src});
while (!pq.empty()) {
    auto [d, u] = pq.top(); pq.pop();
    if (d > dist[u]) continue;              // stale pair: lazy deletion
    for (auto [v, w] : adj[u])
        if (d + w < dist[v]) {
            dist[v] = d + w;
            pq.push({dist[v], v});
        }
}
  • greater<> turns the max-heap into a min-heap; the distance goes first in the pair so it decides the order.
  • The heap cannot lower a key, so an improvement pushes a new pair; the old one is skipped later by d > dist[u].
  • Path sums are long long: a path of 10^5 edges of 10^9 is 10^14.
Dijkstra's frontier: a heap of (distance, vertex) pairs
A→B 5, A→C 1, C→B 2, B→D 1, C→D 6, C→E 7, D→E 2, D→F 6, E→F 1

dist[A] = 0 and every other distance is infinity. The heap holds one pair, (0, A): distance first, so the smallest distance is always on top.

0:01 / 0:29Step 1 of 11
Transcript · 11 steps

Pitfalls

  • Printing LLONG_MAX for an unreachable vertex — map it to -1 (or what the statement asks).
  • pq.push({v, dist[v]}) — the vertex first sorts by vertex number, not distance.
  • Forgetting the stale check: still correct, but a vertex's edges are scanned many times — TLE on dense graphs.

More practice

Common questions

When should I use BFS instead of Dijkstra?

When every edge has the same weight. BFS visits vertices in order of edge count, which is exactly the distance then, in O(V + E) with a plain queue. Dijkstra gives the same answer but pays a log factor for the heap.

What is 0-1 BFS?

A shortest-path algorithm for graphs whose edge weights are only 0 or 1. It keeps a deque: a 0-weight edge pushes the neighbour to the front and a 1-weight edge to the back, so the deque always holds at most two distance values in order. It runs in O(V + E).

Why does Dijkstra fail with negative edge weights?

Dijkstra settles the closest vertex for good, assuming no later path can be shorter. A negative edge reached later can make one shorter, so a settled distance would be wrong. Use Bellman–Ford, or SPFA, when weights can be negative.

What is lazy deletion in Dijkstra?

std::priority_queue cannot lower a key, so when a distance improves you push a new pair and leave the old one. When an old pair is popped, d > dist[v] shows it is stale and you skip it. The heap holds at most E pairs.

Mark as readSign in to keep your place.

Dijkstra's Algorithm in C++ for Contests: BFS and 0-1 BFS

Pick the shortest-path algorithm from the weights: BFS for unit edges, 0-1 BFS with a deque, Dijkstra with a priority queue and lazy deletion in C++.

How do you implement Dijkstra's algorithm in C++?

Dijkstra's algorithm finds shortest distances from one source when every edge weight is non-negative. In C++ keep a dist array at infinity, push {0, source} into a priority_queue ordered smallest first, and repeatedly pop the closest pair: skip it if its distance is stale, otherwise relax each out-edge and push any improved neighbour. It runs in O((V + E) log V).

Lesson

Pick the algorithm from the edge weights, never from habit:

WeightsAlgorithmCost
all equal (grid moves)BFS, queueO(V + E)
only 0 or 10-1 BFS, dequeO(V + E)
non-negativeDijkstra, priority_queueO((V + E) log V)
some negativeBellman–FordO(V · E)

BFS and 0-1 BFS

  • BFS pops vertices in order of edge count; set dist[v] when v is first pushed, and a cell is never queued twice.
  • 0-1 BFS: a 0-edge push_fronts the neighbour, a 1-edge push_backs it. The deque holds at most two distance values, in order, so its front is always a closest vertex.
deque<int> dq{src};
dist[src] = 0;
while (!dq.empty()) {
    int u = dq.front(); dq.pop_front();
    for (auto [v, w] : adj[u])
        if (dist[u] + w < dist[v]) {
            dist[v] = dist[u] + w;
            w == 0 ? dq.push_front(v) : dq.push_back(v);
        }
}

Dijkstra, the contest way

vector<ll> dist(n + 1, LLONG_MAX);
priority_queue<pair<ll,int>, vector<pair<ll,int>>, greater<>> pq;
dist[src] = 0;
pq.push({0, src});
while (!pq.empty()) {
    auto [d, u] = pq.top(); pq.pop();
    if (d > dist[u]) continue;              // stale pair: lazy deletion
    for (auto [v, w] : adj[u])
        if (d + w < dist[v]) {
            dist[v] = d + w;
            pq.push({dist[v], v});
        }
}
  • greater<> turns the max-heap into a min-heap; the distance goes first in the pair so it decides the order.
  • The heap cannot lower a key, so an improvement pushes a new pair; the old one is skipped later by d > dist[u].
  • Path sums are long long: a path of 10^5 edges of 10^9 is 10^14.
512167261ABCDEFdist031467ABCDEFheapempty
Dijkstra's frontier: a heap of (distance, vertex) pairs. Example: A→B 5, A→C 1, C→B 2, B→D 1, C→D 6, C→E 7, D→E 2, D→F 6, E→F 1
  1. dist[A] = 0 and every other distance is infinity. The heap holds one pair, (0, A): distance first, so the smallest distance is always on top.
  2. Pop (0, A): A is settled at 0. Relax its edges: B ∞ → 5, C ∞ → 1.
  3. Pop (1, C): C is settled at 1, since no path through a later vertex can be shorter. Relax its edges: B 5 → 3, D ∞ → 7, E ∞ → 8.
  4. Pop (3, B): B is settled at 3, since no path through a later vertex can be shorter. Relax its edges: D 7 → 4.
  5. Pop (4, D): D is settled at 4, since no path through a later vertex can be shorter. Relax its edges: E 8 → 6, F ∞ → 10.
  6. Pop (5, B): stale, because dist[B] is already 3. Lazy deletion just skips it — the check d > dist[v] is one line.
  7. Pop (6, E): E is settled at 6, since no path through a later vertex can be shorter. Relax its edges: F 10 → 7.
  8. Pop (7, D): stale again — dist[D] is 4. Skipped.
  9. Pop (7, F): settled at 7. None of its edges improves anything.
  10. Every pair left is stale: (8, E) against dist 6, (10, F) against dist 7. Each pop is skipped in O(log V).
  11. The heap is empty. Final distances from A: A 0, B 3, C 1, D 4, E 6, F 7. Each vertex settled once; each edge relaxed at most once: O((V + E) log V).

Pitfalls

  • Printing LLONG_MAX for an unreachable vertex — map it to -1 (or what the statement asks).
  • pq.push({v, dist[v]}) — the vertex first sorts by vertex number, not distance.
  • Forgetting the stale check: still correct, but a vertex's edges are scanned many times — TLE on dense graphs.

More practice

Common questions

When should I use BFS instead of Dijkstra?

When every edge has the same weight. BFS visits vertices in order of edge count, which is exactly the distance then, in O(V + E) with a plain queue. Dijkstra gives the same answer but pays a log factor for the heap.

What is 0-1 BFS?

A shortest-path algorithm for graphs whose edge weights are only 0 or 1. It keeps a deque: a 0-weight edge pushes the neighbour to the front and a 1-weight edge to the back, so the deque always holds at most two distance values in order. It runs in O(V + E).

Why does Dijkstra fail with negative edge weights?

Dijkstra settles the closest vertex for good, assuming no later path can be shorter. A negative edge reached later can make one shorter, so a settled distance would be wrong. Use Bellman–Ford, or SPFA, when weights can be negative.

What is lazy deletion in Dijkstra?

std::priority_queue cannot lower a key, so when a distance improves you push a new pair and leave the old one. When an old pair is popped, d > dist[v] shows it is stale and you skip it. The heap holds at most E pairs.

Exercises

Escape the grid

A grid of R rows and C columns holds . (open), # (wall), exactly one S and exactly one T. Each move goes one cell up, down, left or right, onto any cell that is not a wall. Print the fewest moves from S to T, or -1 if T cannot be reached.

Input: R C, then R lines of C characters (1 ≤ R, C ≤ 1000). Output: one integer.

4 5
S..#.
.#...
...#T
.#...

prints

6

Free corridors, paid doors

A directed graph has vertices 1 to n and m edges, each of weight 0 or 1. Print the shortest distance from vertex 1 to every vertex, -1 for one that cannot be reached.

Input: n m, then m lines u v w with w in {0, 1} (1 ≤ n ≤ 2·10^5, 0 ≤ m ≤ 2·10^5). Output: n integers on one line, separated by spaces.

5 6
1 2 1
1 3 0
3 2 0
2 4 1
3 4 1
4 5 0

prints

0 0 0 1 1

In this module: Shortest paths: BFS, 0-1 BFS, Dijkstra

← Checkpoint — Disjoint set union · Checkpoint — Shortest paths →