Shortest Path Problem Variants
What This Concept Is
"Shortest path" is not a single problem. It is a family of problems parameterized by three independent choices:
- Source structure. Single-source (
SSSP), single-pair (stot), all-pairs (APSP), or multi-source (shortest from any of several sources). - Edge weights. All unit, nonnegative, real-valued with possible negative edges, or permitting negative cycles.
- Path cost. Sum of edge weights (classical), max of edge weights (bottleneck), product (multiplicative), or more exotic aggregations.
The combination decides which algorithm can run:
| Weights | SSSP | APSP |
|---|---|---|
| unit | BFS in `O( | V |
| nonnegative | Dijkstra in `O(( | V |
| real, no negative cycles | Bellman-Ford in `O( | V |
| negative cycle present | no finite shortest path; detect instead | detect instead |
| DAG, any weights | topo-order relax in `O( | V |
Two algorithmic families drive this landscape: greedy (Dijkstra, pick closest unfinalized) and relaxation-based DP (Bellman-Ford, Floyd-Warshall). Dijkstra is faster but constrained to nonnegative weights; Bellman-Ford is more general but slower. Floyd-Warshall is the cleanest way to get APSP if the graph is dense and small.
Distinguish sharply: Dijkstra vs Bellman-Ford differ on negative-edge handling (Dijkstra breaks); BFS vs Dijkstra differ on unweighted vs weighted (BFS is faster on unweighted); Floyd-Warshall vs Johnson's differ on density (FW wins dense, Johnson's wins sparse).
Why It Matters Here
Most shortest-path bugs are variant mismatches: running the wrong algorithm for the problem you actually have. Before coding anything, you must state exactly which variant you are solving. That decision pre-determines what correctness even means - if negative cycles are present, there is no shortest simple path in general, so the right question becomes "detect the negative cycle" rather than "find a distance."
The pattern repeats throughout the semester: naming the problem variant is half the solve.
Concrete Example
Three near-identical-sounding problems:
- "Shortest driving distance from my house to every park in the city." Graph has nonnegative mile weights. Variant: SSSP, nonnegative weights -> Dijkstra.
- "Most profitable sequence of currency trades starting from USD." Graph has real-valued log-rate weights (and possibly negative). Variant: SSSP, possibly negative edges, want negative-cycle detection -> Bellman-Ford.
- "Fastest travel time between every pair of cities on a small country-wide network of
500airports." Variant: APSP, nonnegative weights, dense-ish graph -> Floyd-Warshall (simplest) or repeated Dijkstra (if sparse).
Picking the wrong one gives you a running algorithm with an incorrect answer, not a crash.
A visual comparison on the same tiny graph:
- BFS (pretending weights are
1): returnss -> tvia2edges throughb. - Dijkstra (honoring weights): returns
s -> b -> a -> twith cost1+2+3=6. - Bellman-Ford: same answer as Dijkstra (no negative edges).
- Floyd-Warshall: produces shortest distances between every pair.
Change one edge to negative and Dijkstra can silently produce a wrong answer while Bellman-Ford still works.
Common Confusion / Misconceptions
- "Shortest silently assumes additive cost." If the path cost is
max of edge weights(bottleneck shortest path), standard Dijkstra with addition is wrong; you need a modified relaxation usingmaxinstead of+(the monoid changes). Any MST already solves bottleneck shortest paths along tree edges. - "Dijkstra fails loudly on negative weights." It does not. It produces a plausible-looking wrong answer. This is the dangerous mode of failure.
- "Bellman-Ford is only for negative edges." It works with nonnegative edges too, just slower than Dijkstra. Its real job is negative-cycle detection.
- "APSP always needs Floyd-Warshall." For sparse graphs with nonnegative weights, running Dijkstra from each vertex beats Floyd-Warshall asymptotically:
O(V(V+E) log V) = O(V^2 log V + VE log V)vsO(V^3). - "Multi-source is a new algorithm." It is not. Push all sources into the priority queue (Dijkstra) or queue (BFS) at distance
0; the rest is unchanged.
How To Use It
Use this decision flow before choosing an algorithm:
- Is the graph a DAG? If yes, relax edges in topological order in
O(|V|+|E|). - Are edge weights all equal or unit? Use BFS (or 0-1 BFS for
{0,1}weights). - Are all weights nonnegative? Use Dijkstra.
- Are some weights negative? Use Bellman-Ford; it also detects negative cycles.
- Need distances between every pair, and the graph is small-ish (hundreds to low thousands of vertices)? Use Floyd-Warshall.
- Need APSP on a large sparse graph with nonnegative weights? Run Dijkstra from every source (or use Johnson's if negative edges are present but no negative cycles).
- Is the cost aggregation non-additive (max, product, probability)? Adapt relaxation to the correct monoid.
Write your answer down before writing code. The commentary you would have placed above the #include line is what you should have written on paper before starting.
Transfer / Where This Shows Up Later
- S3 (systems). Routing tables on operating systems and network stacks are shortest-path results; OSPF uses Dijkstra variants, BGP uses distance-vector variants (Bellman-Ford family).
- S4 (compilers). Register-pressure-aware instruction scheduling minimizes weighted paths in the DAG of scheduled instructions.
- S5 (OS). Priority inheritance chains in mutex systems use longest-path-in-DAG.
- S6 (databases). Query optimizers pick plans by cost, effectively doing shortest path in the plan graph. Graph databases (Neo4j, JanusGraph) expose shortest-path queries directly.
- S7 (architecture). "Blast radius" is a shortest-path query on the service-dependency graph with weighted edges for call latency.
- S8 (distributed). Routing in SDN, mesh networks, and content delivery uses Dijkstra-family algorithms with periodic recomputation.
Back-link to S1 M2 for graph distance definitions and to M4 greedy algorithms for the greedy-choice proof that Dijkstra leans on.
Check Yourself
- Why can't Dijkstra handle negative edges even when there is no negative cycle?
- When does a shortest path fail to exist as a finite simple path?
- What does "bottleneck shortest path" mean, and which aggregation replaces addition?
- For a DAG, why is shortest-path work linear in
|V| + |E|regardless of weight signs? - Explain why multi-source BFS/Dijkstra require no algorithmic change beyond initialization.
- Which algorithm would you use for APSP on
|V| = 10^5,|E| = 10^6, weights nonnegative? Justify.
Mini Drill or Application
For each scenario, identify the variant (source structure, weights, path cost) and the best-fit algorithm:
- Social-graph degrees of separation between two users.
- Minimum-fee money transfer across a network of banks where some fees are negative rebates.
- Maximum-reliability communication path where each link has an independent success probability.
- Shortest-expected-time path in a road network with deterministic travel times.
- Checking whether arbitrage is possible across
kcurrencies with exchange rates. - Shortest number of moves for a knight to reach a square on an infinite chess board.
- Minimum-latency path in a cloud region, where edges are latency and vertices are regions.
Then write one line of justification per choice.
Implementation drill. Given a graph library of your choice (yours or NetworkX), pick a single real dataset (e.g., SNAP road networks) and run BFS, Dijkstra, Bellman-Ford, and Floyd-Warshall (where feasible) on the same source vertex; verify the answers agree, and plot wall-clock time vs |V|.
Read This Only If Stuck
- CLRS 22.5: Shortest-Paths Properties
- CLRS 22.5: Shortest-Paths Properties (Part 2)
- CLRS 22.2: SSSP in DAGs
- CLRS 22.4: Difference constraints and shortest paths
- Competitive Programming 4.4: SSSP overview
- Competitive Programming 4.4.2: SSSP on unweighted graph
- Competitive Programming 4.4.3: SSSP on weighted graph
- ADM 6.3.1: Dijkstra
- ADM 6.3.2: All-Pairs Shortest Path
- cp-algorithms: Dijkstra (dense)
- Sedgewick & Wayne, algs4 booksite: Shortest Paths