Question bank — Dijkstra's algorithm — greedy, priority queue, O((V+E) log V) — no negative edges
This page is a companion to the parent Dijkstra note — every claim here refers back to the invariant, the relaxation rule, or the lazy-heap mechanics it built.
Vocabulary you need before the questions
To answer honestly you must share the exact meaning of five words. Each is anchored to a picture below.
The figure below shows the whole flooding picture these words describe.

And here is the worked-example graph and its heap snapshots, so the "pop C before B" question later has something concrete to point at.

True or false — justify
Every answer below is "true because…" or "false because…". A bare T/F earns nothing — the reason is the point.
Dijkstra always visits vertices in order of increasing final distance from the source.
If a graph has one negative edge but no negative cycle, Dijkstra still gives correct answers.
Adding a large positive constant to every edge weight, running Dijkstra, then subtracting, recovers correct shortest paths.
Dijkstra with all edge weights equal to produces the same shortest-path distances as BFS.
If dist[v] never changes after the first time we relax it, then v had no shorter path.
dist[v] can be relaxed multiple times and decrease each time before v is popped; it only becomes final at pop. "First relaxation is final" is a common trap.Once a vertex is pushed onto the priority queue, we can safely mark it visited.
With a lazy heap, the same vertex can be popped more than once.
if d > dist[u]: continue.Dijkstra requires the graph to be connected.
dist = INF and are never popped; the algorithm terminates fine. Connectivity is not assumed anywhere in the proof.Dijkstra works on both directed and undirected graphs.
Removing the if d > dist[u]: continue line makes Dijkstra produce wrong shortest-path distances.
dist[] values still come out correct, because a stale pop can only try to relax with an already-larger d and every such relaxation fails the < test. What you lose is efficiency: you waste time re-scanning neighbors from outdated entries. Keep the line, but for correctness of the numbers it is an optimization, not a fix.Spot the error
Each item describes a buggy belief or code choice. Name what breaks.
"I finalize a vertex the moment I update its distance."
"To find the longest path I just negate all weights and run Dijkstra."
"My PQ stores only the vertex id, and I look up its distance when I pop."
d against current dist[u]), so lazy deletion silently fails."I initialize dist[s] = 0 but leave all others at 0 too."
INF; starting them at 0 means no relaxation ever fires (dist[u]+w < 0 is false), so you return all zeros."I stop as soon as I pop the target t, so I skip the stale-check."
t is non-stale — a stale t pop carries an inflated distance and would return a wrong answer if you trust it."I use Dijkstra to build a Minimum Spanning Tree."
"A* is always faster than Dijkstra so I use A* everywhere."
Why questions
Reasoning, not recall — explain the mechanism. (Recall = true shortest distance, = current guess, from the vocabulary box above.)
Why does the correctness proof use non-negativity exactly once, and where?
Why is popping the minimum tentative distance the crucial choice?
Why does a lazy heap let us avoid a decrease-key operation?
Why is the complexity and not ?
Why does a Fibonacci heap improve the bound to ?
Why does Dijkstra count as a greedy algorithm rather than dynamic programming?
Why can we relax the same edge only once effectively?
dist[u] never changes — so relaxing again would use the same values and change nothing.In the worked-example graph (second figure), why does the heap pop C(1) before B(4) even though B was updated first?
Edge cases
The scenarios people forget to test.
What happens on a graph with zero-weight edges?
What does Dijkstra return for a vertex unreachable from the source?
INF (the "no path yet" sentinel from the vocabulary box) — never pushed, never popped — correctly signalling "no path exists". No special-casing needed.What if the source has a self-loop with weight ?
dist[s]=0 is never overwritten. Self-loops are harmless.What if two different paths to a vertex have equal total weight?
dist[v] records the shared minimum; which predecessor you keep depends on relaxation order and is an arbitrary but valid shortest path. All ties are correct answers.What about a graph with multiple edges (parallel edges) between the same pair, different weights?
dist[u]+w sticks. No preprocessing required.What happens on a single-vertex graph (just the source)?
dist[s]=0 is pushed, popped, has no outgoing edges to relax, PQ empties — the algorithm returns {s:0} immediately. A clean degenerate base case.What if every edge weight is identical (say all )?
Recall One-line self-test
Cover the reveals above. If you can state why each trap is a trap (invariant, pop-vs-push finalization, lazy staleness, non-negativity) without peeking, you own the concept — not just the code.
Connections
- Bellman-Ford algorithm — the fallback when non-negativity fails
- BFS — the unit-weight / equal-weight degenerate case
- A* search — Dijkstra plus a target heuristic
- Priority Queue (Binary Heap) — where the and the decrease-key story live
- Greedy algorithms — the invariant/exchange justification
- Prim's algorithm — same heap, different relaxation key
- Johnson's algorithm — correct reweighting for negative edges