Network Flow
How much can flow through a network from source to sink? We build flow networks with capacity and conservation constraints, increase a flow by pushing along augmenting paths in the residual graph, and see how reverse edges let the algorithm undo earlier routing.
╌╌╌╌
Imagine a network of pipes carrying water from a source to a sink, each pipe with a maximum capacity. How much water can you push through end to end? This is the maximum flow problem, and its reach extends far past plumbing: routing traffic, scheduling jobs, matching applicants to jobs, even segmenting images all reduce to it. Max-flow is one of algorithm design's great modeling tools; the art, as Erickson stresses, lies in recognizing a flow problem.1
Flow networks
Think of routing a single commodity (water, electricity, traffic, money) from a source to a sink across a network whose edges have limited throughput.
A flow is a function on the edges. The single most useful piece of bookkeeping is the net flow out of a vertex , written using the boundary symbol :
A flow is feasible when it obeys two rules:
- Non-negativity & capacity. for every edge: no edge runs backward, and none carries more than its capacity.
- Conservation. for every vertex : nothing is created or destroyed at an interior node. (When conservation holds at every vertex, is a circulation.)
The value of an – flow is the net amount leaving the source, . A short computation shows this is the same as the net amount arriving at the sink: summing over all vertices counts each edge's flow once with a and once with a , so ; conservation kills every interior term, leaving , i.e. . The maximum-flow problem is to find a feasible flow of greatest value.
Below is a worked network; each edge is labeled (flow over capacity), realizing units pushed from to :
Conservation is the statement that each interior node balances. Take vertex : its incident flows are the outgoing , , and the incoming , so
The same check at reads , and at the source . Checking at every interior vertex this way is how you verify a flow is feasible.
Augmenting paths and the residual graph
How do we increase a flow? Find a path from to that still has spare room and push more along it. The bookkeeping device that makes this precise, and makes the algorithm correct, is the residual graph.
Concretely, each original edge splits into three cases on its residual capacity :
- If (empty), put with .
- If (partly used), put both: with , and with .
- If (saturated), put only the reverse with .
(We assume has no anti-parallel edges, at most one of , is in , so these reverse edges are unambiguous. Any graph can be preprocessed to satisfy this by splitting an edge through a dummy vertex.)
The backward edges are the subtle part that matters: pushing flow along cancels existing flow on , letting the algorithm undo earlier,
suboptimal decisions. That is why a greedy fill paths until stuck
approach can get stuck below optimum, while augmenting paths cannot. Below, the
feasible flow from the worked network (top, with vertex omitted since all
of its edges are empty) and the residual graph it induces (bottom); each
residual edge is labeled with its capacity :
A single augmentation is easy to picture on a small network. Each edge below is labeled ; the highlighted residual path has residual capacities , so its bottleneck is . Pushing one unit along it saturates and lifts the flow value from to , with every interior vertex still balanced:
Why the back edges matter
It is tempting to skip the reverse edges entirely: repeatedly find an – path with spare forward capacity, saturate it, and stop when none remains. This greedy scheme is wrong, and the smallest counterexample shows why. Take the diamond below, every edge of capacity ; its maximum flow is (route and ). Suppose greedy first picks the zigzag path and pushes along it. Now every remaining forward option is blocked: has spare room but is saturated, and has spare room but is saturated. Greedy halts at value , half the optimum.
The residual graph repairs exactly this. Because carries flow , contains the reverse edge with capacity , and the path becomes available. Pushing along it cancels the unit on (its flow drops back to ), rerouting the first unit through while the new unit takes . No water flows backward; the algorithm has merely revised an earlier routing decision:
The augmentation lemma
Before trusting the algorithm we must prove that augmenting actually produces a better feasible flow. Augmenting along a path by amount produces a new function defined edge-by-edge:
So every augmentation strictly increases the value while keeping legal. The converse, which the min-cut proof will need, also holds: if is not maximum, must contain an augmenting path. Putting the two together gives the equivalence at the center of the theory
Ford-Fulkerson and Edmonds-Karp
The method is then simple: while an augmenting path exists, push flow along it.2
- 1foreach edge do
- 2
- 3while there exists an augmenting path from to in do
- 4bottleneck
- 5foreach edge on do
- 6push forward
- 7cancel on reverse edge
- 8return
Running time rests on an invariant: if every capacity is an integer, , then all residual capacities and flow values stay integers throughout. Each augmentation then raises by at least , so there are at most iterations, each costing to find a path and push along it (here , ):
If additionally every capacity lies in , then , giving . This is pseudo-polynomial: fine for small capacities, but very slow when they are huge. The classic bad case has a middle edge of capacity between two paths of capacity ; a naïve solver alternately pushes one unit forward and one unit back, taking augmentations. (On irrational capacities the method may not even terminate.)
The fix, due to , is to always pick the shortest augmenting path (fewest edges): find it with BFS in the residual graph.
- 1foreach edge do
- 2
- 3while BFS finds a shortest path from to in do
- 4augment along by its bottleneck
- 5return
Why should the shortest path be any better? The analysis rests on a monotonicity property of BFS levels in the residual graph. Write for the number of edges on a shortest path in .
Counting iterations now follows from a charging argument on critical edges. In each augmentation, at least one residual edge on the path has equal to the bottleneck; that edge is critical and disappears from . For to become critical again, the reverse must first appear on some later shortest path, which requires at the first event and at the second. With the monotone lemma,
so 's level rises by at least between consecutive criticalities of . Levels live in (once the vertex is unreachable and the edge never reappears on a path), so each of the at most residual edges is critical times, giving augmentations in total. Each iteration is one BFS plus one path update, work, for a strongly polynomial bound independent of capacities:
For dense graphs this is far from the last word — Orlin's 2012 algorithm runs in , and you may cite max-flow as an black box — but is the version to know: two ideas (residual graph, BFS) and a clean proof.
A complete run of Edmonds-Karp
Here is one full run, end to end. The network below has six vertices and seven edges (capacities on the edges); we run from the zero flow, scanning neighbors in alphabetical order so the BFS choices are reproducible. Each round we show the residual graph, the shortest augmenting path BFS finds (highlighted), and the bottleneck it pushes.
Round 1. With the residual graph is : every edge appears forward at full capacity. BFS layers the vertices and returns the length- path . Its residual capacities are , so the bottleneck is : push , and the value rises .
Round 2. Edge is now saturated and survives only as the reverse edge ; keeps forward capacity plus a reverse edge of capacity . BFS finds with residual capacities ; the bottleneck is . Push : the value rises , and both and saturate.
Round 3. The source's only remaining forward edge is . BFS finds with residual capacities (edge has left); the bottleneck is . Push : the value rises , and saturates.
Round 4 (halt). BFS from now reaches (forward capacity remains on ), then (via , capacity ), then (via the reverse edge ) — and stops. Every edge out of this set is saturated, so is unreachable and the algorithm halts with .
The whole run in one table:
| Round | Augmenting path | Residual capacities | Bottleneck | Value |
|---|---|---|---|---|
| 1 | ||||
| 2 | ||||
| 3 | ||||
| 4 | none — unreachable | — | — |
The final flow, edge by edge: , , , , , , . Every interior vertex balances (: in , out ; : in , out ; : in , out ; : in , out ), and . Is really the maximum? The halting condition says yes, but the certificate that proves it is a cut — the subject of the next lesson, where this same network returns.
This continues in Max-Flow Min-Cut and Applications. There we prove why the halting flow is optimal — the max-flow min-cut theorem — and apply the abstraction to bipartite matching and a catalog of modeling reductions.
Footnotes
- Erickson, Ch. 10 & 11 — Maximum Flows and Applications — the art of recognizing a problem as a flow problem. ↩
- CLRS, Ch. 26 — Maximum Flow — the Ford-Fulkerson method augmenting along residual paths. ↩
- CLRS, Ch. 26 — Maximum Flow — the Edmonds-Karp analysis via monotone shortest-path distances in the residual graph. ↩
╌╌ END ╌╌