The decision tree, before anything else:

unweighted?              -> BFS                       O(V+E)
weights in {0,1}?        -> 0-1 BFS                   O(V+E)
small integer weights?   -> Dial's algorithm          O(VC+E)
acyclic (DAG)?           -> topological DP            O(V+E)   [negatives OK]
non-negative weights?    -> Dijkstra                  O(E log V)
negative weights?        -> Bellman-Ford / SPFA       O(VE)
all pairs, V <= 500?     -> Floyd-Warshall            O(V^3)
all pairs, sparse?       -> Johnson                   O(VE + V^2 log V)
good heuristic available?-> A*

The relaxation invariant

Every shortest-path algorithm is the same operation repeated:

They differ only in the order in which edges are relaxed:

AlgorithmRelaxation order
BFSby increasing hop count
Dijkstraby increasing tentative distance (greedy)
DAG DPtopological
Bellman-Fordall edges, times
SPFAonly vertices whose distance changed
Floyd-Warshallby allowed intermediate vertex

Properties worth knowing

  • Optimal substructure. Any subpath of a shortest path is a shortest path. This is what makes DP and greedy both applicable.
  • Shortest path tree. The union of one shortest path to each vertex forms a tree rooted at the source (with consistent tie-breaking).
  • At most edges. A shortest path never repeats a vertex when there are no negative cycles — hence Bellman-Ford’s rounds.
  • Reweighting. Given potentials , replacing by changes every path by the same constant, preserving the shortest path set. This is the trick behind Johnson, Suurballe, and min-cost flow with Dijkstra.

Common variants

VariantApproach
Path reconstructionstore par[v] on each successful relaxation
Count the number of shortest pathskeep cnt[v]; on < reset, on == add
Second shortest pathkeep the best two distinct distances per vertex in the priority queue
Shortest path with exactly edgeslayered graph: state
Shortest path visiting required verticesbitmask state ,
Minimise the maximum edge (bottleneck)binary search + BFS, or MST path max, or Dijkstra with max instead of +
Maximise the minimum edgesame, reversed — the MST maximises this
Minimum edges among shortest pathsDijkstra on the pair (dist, edges)
Shortest path with one edge free / halvedlayered graph with one “used the discount” bit
Shortest cycle through a vertexDijkstra from it, then check back edges
Shortest even/odd length pathlayered graph with a parity bit

The bottleneck path trick

“Minimise the largest edge on the path” is not a sum, but the same greedy works: run Dijkstra with

if (max(dist[u], w) < dist[v]) dist[v] = max(dist[u], w);

Equivalently, the answer is the maximum edge on the path between the two vertices in the minimum spanning tree — a fact worth remembering, because it turns bottleneck queries into path-max queries on a tree, answerable with binary lifting in each.

Negative weights: what breaks

Dijkstra assumes that once a vertex is popped its distance is final, which relies on all weights being non-negative. With a negative edge, a later, longer-looking path can improve an already-finalised vertex. The failure is silent — Dijkstra returns a plausible wrong answer rather than crashing. Use Bellman-Ford, or reweight with Johnson first.

See also: Complexity Cheatsheet · Negative Cycles · DAG Shortest Paths