The shortest-path problem is already on this course: one unit supplied at the source, one demanded at the sink, and the costs read as lengths. What is new here is its dual, which is worth writing down because the labels every shortest-path algorithm computes turn out to be a feasible point of it.
Definition · Node potentialsA vector π, one number per node, is feasible for the shortest-path dual when πⱼ − πᵢ ≤ cᵢⱼ for every arc from i to j. The dual problem is to maximise πₜ − πₛ over all such vectors.
An arc is tight when the inequality holds with equality. The reduced cost of an arc is cᵢⱼ − (πⱼ − πᵢ), which is non-negative exactly when π is feasible.
The constraint says something plain: the price at the head may exceed the price at the tail by at most the cost of getting there. Any feasible π therefore has πₜ − πₛ at most the cost of every path from source to sink — add the constraints along the path and the intermediate terms cancel — so the dual objective is a lower bound on the shortest path. That is weak duality, in one line, with no machinery.
arcs s>a 4 s>b 2 b>a 1 a>t 3 b>t 7
relaxation, one round = one pass over the arcs in the order typed
round 0 s 0 a - b - t -
round 1 s 0 a 3 b 2 t 6
round 2 s 0 a 3 b 2 t 6 nothing moved, stop
check every arc: c - (pi_j - pi_i)
s>a 4 - (3 - 0) = 1 slack
s>b 2 - (2 - 0) = 0 TIGHT
b>a 1 - (3 - 2) = 0 TIGHT
a>t 3 - (6 - 3) = 0 TIGHT
b>t 7 - (6 - 2) = 1 slack
dual objective pi_t - pi_s = 6 - 0 = 6
the tight arcs are exactly the route s, b, a, t, which costs 6
Two things about that table are worth noticing. The first is that a ends at 3 rather than 4: the direct arc costs 4 and the route through b costs 2 + 1 = 3, so the direct arc ends up slack. The second is that one pass over the arcs was enough, because the order they were typed in happened to relax them usefully; the second round is what proves it, by changing nothing.
The shift, and why the labels are prices
Example · Add seven to everythingTake the labels 0, 3, 2, 6 and add 7 to each, giving 7, 10, 9, 13. Every arc constraint still holds — each is a difference, and the seven cancels — and the dual objective is still 13 − 7 = 6. The same tight arcs are still tight.
Now add 5 to one label only. The lab reports the arcs that are violated, in red. This is the contrast that makes the point: the vector floats as a whole and does not float component by component, which is precisely the behaviour of a price.
This is why the lesson is called potentials rather than distances. Calling them distances is not wrong — the normalisation πₛ = 0 makes each label the distance from the source — but it hides the fact that the object is determined only up to a constant, and it makes the next two courses harder than they need to be, where the same potentials are used to reprice a network without changing which route is cheapest.
Example · A negative arc is fines>a 4, s>b 2, a>b −3, b>t 2, a>t 6 has a negative cost on it, and the labels settle at 0, 4, 1, 3 with s>a, a>b and b>t tight. The cheapest way to b is through a at 4 − 3 = 1, not the direct arc at 2.
So a negative cost is not a problem in itself — it is perfectly meaningful when an arc earns rather than spends. What cannot be tolerated is a cycle whose total is negative, which is a different thing entirely.
When no potentials exist
Example · Three arcs and no feasible dual pointx>y 1, y>z −3, z>x 1, x>z 5. Add the dual constraints round the cycle x, y, z, x: the labels cancel and what is left is 0 ≤ 1 + (−3) + 1 = −1. No vector π can satisfy all three, so the dual is infeasible.
The relaxation finds this by still improving when it should have stopped: the labels go 0, ∞, ∞ then −1, 1, −2 then −2, 0, −3 then −3, −1, −4, one unit lower every round and never settling. The lab names the cycle y, z, x and reports that it costs −1.
The word for this on the primal side is unbounded: send a unit round that cycle as many times as you like and the cost falls without limit. An unbounded primal and an infeasible dual are the pair the duality course described, and here they arrive as a picture you can point at.
One thing deliberately absent from this page is a second algorithm. Dijkstra's algorithm computes the same labels faster on non-negative costs, it belongs to Discrete Mathematics' “Shortest Paths and Dijkstra's Algorithm”, and putting it beside this one would invite the question “which is better” when the question here is “what are these numbers”. They are a dual solution. That is the lesson.