A Bit of History
As introduced in Part 15, L. R. Ford Jr. and D. R. Fulkerson published “Maximal Flow Through a Network” in 1956. Their work grew from questions about the throughput and bottlenecks of transportation networks. The method and the max-flow min-cut theorem fit together unusually well: one constructs a better flow, while the other supplies a certificate that no better flow can exist.
The Flow Model
A flow network is a directed graph with a nonnegative capacity $c(u,v)$ on every edge, a source $s$, and a sink $t$. A candidate flow $f$ is feasible only when it obeys two rules:
Never exceed an edge
For every edge, $0\le f(u,v)\le c(u,v)$. A pipe cannot carry more than its rated capacity.
Intermediate vertices store nothing
At every $v\notin\{s,t\}$, total inflow equals total outflow.
Maximize source-to-sink throughput
The flow value $|f|$ is the net amount leaving $s$, equivalently the net amount entering $t$.
Capacity is a constraint, not an instruction. An edge of capacity 10 may carry any feasible amount from 0 through 10. The algorithm’s job is to coordinate all those local choices into the largest possible global throughput.
Working Principle
Ford–Fulkerson is called a method because it does not prescribe how to choose the next path. DFS, BFS, or another search rule may be used. Everything else follows the same loop:
- Start with zero flow, so every original capacity is available.
- Build or maintain the residual graph: the graph of adjustments still allowed.
- Find any source-to-sink path whose residual edges are all positive.
- Let $\Delta$ be the smallest residual capacity on that path—the bottleneck.
- Push $\Delta$ units along the path: subtract it from forward residual edges and add it to reverse residual edges.
- When no augmenting path exists, stop.
The bottleneck is the most that can be added without violating capacity. At least one residual edge becomes zero after each augmentation, although later reverse-edge use may make it available again.
Residual Networks: The Algorithm’s Memory
For one original edge $u\to v$ with capacity $c$ and current flow $f$, the residual graph records two different freedoms:
Worked Example
Consider capacities $S\to A=3$, $S\to B=2$, $A\to T=2$, $B\to T=3$, and $A\to B=1$. We label the final edges as flow / capacity.
Why the third path matters
After the first two augmentations, the flow value is 4, but one unit remains on $S\to A$, $A\to B$, and $B\to T$. The third path combines those leftovers. Ford–Fulkerson does not require all useful paths to be obvious in the original network; it only asks whether the current residual graph contains one.
Why It Is Correct
Every augmentation preserves feasibility. Choosing $\Delta$ as the bottleneck prevents any forward residual capacity from becoming negative, and the paired forward/reverse update preserves flow conservation at internal vertices.
Now suppose the method stops. Let $R$ be the set of vertices reachable from $s$ in the final residual graph. The sink is not in $R$, or there would still be an augmenting path. For every original edge from $R$ to $V\setminus R$, the forward residual capacity is zero, so that edge is saturated. Any edge pointing back into $R$ carries no net flow across the cut in the wrong direction; otherwise its reverse residual edge would make the outside endpoint reachable.
Therefore the current flow value equals the capacity of the cut $(R,V\setminus R)$. Every feasible flow is at most every cut capacity, so this flow is maximum and this cut is minimum.
The Cut Is a Verifiable Certificate
You do not have to replay the path sequence. Compute the capacity of the returned source-side cut and compare it with the reported flow value. A full audit can additionally expose the per-edge flow and verify capacity and conservation; equality between a feasible flow and a cut proves optimality.
Complexity Analysis
Assume capacities are nonnegative integers and a DFS finds each augmenting path in $O(E)$. Every augmentation raises the flow value by at least 1. If the maximum value is $F$, there can be at most $F$ augmentations:
$$\text{Time: } O(EF) \qquad \text{Space: } O(V+E)$$
This is pseudo-polynomial: the bound depends on the numeric value $F$, not merely the number of bits used to encode the input. Writing a capacity of one billion takes only about 30 bits, yet the bound permits one billion augmentations.
| Capacity type | Termination | What the usual bound says |
|---|---|---|
| Integer | Guaranteed | At most $F$ augmentations; $O(EF)$ with DFS |
| Rational | Guaranteed after scaling to integers | The scaled values may make the pseudo-polynomial bound very large |
| Irrational | Not guaranteed for arbitrary path choices | An adversarial sequence can keep augmenting forever and need not reach the maximum |
A Pathological Case
Path Choice Is the Unspecified—and Dangerous—Part
On a small integer-capacity network, an unlucky DFS order can repeatedly choose paths whose bottleneck is 1 even while a huge amount of flow remains possible. With capacities in the millions, that means millions of searches. With irrational capacities, carefully chosen augmenting paths can even prevent termination. Ford–Fulkerson describes the improvement framework; the path-selection rule determines its performance.
Edmonds–Karp removes this ambiguity by always choosing a shortest augmenting path in edge count using BFS. That single rule gives a capacity-independent polynomial bound of $O(VE^2)$.
Implementation
The implementations use DFS to choose augmenting paths, so they are Ford–Fulkerson rather than Edmonds–Karp. They construct a private residual graph, reject negative capacities and the ambiguous $s=t$ case, aggregate repeated directed edges, and return the final source-side set $R$ of the minimum cut.
| Structure | Meaning | Invariant |
|---|---|---|
residual[u][v] | Additional net flow currently allowed from $u$ to $v$ | Never negative |
adj[u] | Both original and reverse neighbors | Every residual edge can be traversed when positive |
parent | One DFS tree in the residual graph | Reconstructs an augmenting path only when it reaches $t$ |
source_side | Vertices reachable from $s$ after termination | Defines a minimum cut |
Real-World Applications
Max flow models a transferable quantity limited by local bottlenecks. The “quantity” need not be literal fluid; it can represent shipments, connections, assignments, or any interchangeable unit.
Throughput and bottleneck planning
Warehouses become vertices and shipping lanes become capacitated edges. The max flow estimates sustainable throughput; the min cut identifies the lanes jointly limiting it.
Bandwidth allocation
Links carry capacities and routers connect them. The model reveals an upper bound on single-commodity transfer and the links whose expansion could remove the current bottleneck.
Bipartite assignment
Connect the source to left-side vertices, compatible pairs across the partition, and right-side vertices to the sink, all with unit capacity. Integral max flow then encodes a matching.
Edge-independent connectivity
Giving every edge capacity 1 turns the max-flow value into the maximum number of edge-disjoint source-to-sink paths.
When the model needs more than max flow
Basic max flow optimizes quantity only. If edges have prices, delays, or preferences, use minimum-cost flow. If several unrelated commodities share capacity, ordinary single-commodity max flow is no longer enough. Modeling the right state and constraints matters as much as choosing the algorithm.
Choosing a Flow Algorithm
| Method | Path or update rule | Typical guarantee | Good fit |
|---|---|---|---|
| Ford–Fulkerson | Any augmenting path | $O(EF)$ for integer capacities with $O(E)$ path search | Teaching, small integral instances, simple prototypes |
| Edmonds–Karp | BFS shortest augmenting path | $O(VE^2)$ | Predictable polynomial behavior and straightforward code |
| Dinic | Level graphs and blocking flows | $O(V^2E)$ on general networks | Larger sparse networks and competitive programming |
| Push–relabel | Local excess pushes, no path search | $O(V^3)$ with a basic implementation | Dense networks and high-performance implementations |
These are not different optimization problems: they all compute maximum flow. They differ in how they organize residual updates and therefore how much redundant work they can avoid.
Pitfalls & Debugging
| Symptom | Likely cause | Fix |
|---|---|---|
| The answer is too small | Reverse residual edges were not added to adjacency | Add both $u\to v$ and $v\to u$ as searchable neighbors, even when reverse capacity begins at 0 |
| A residual capacity becomes negative | The path bottleneck was computed incorrectly or updates used the wrong orientation | Reconstruct $s\to t$ consistently and use one $\Delta=\min c_f(u,v)$ for the entire path |
| The program never finishes for $s=t$ | The empty path has no finite bottleneck | Reject or define this case before entering the augmentation loop |
| Large tests overflow | Flow totals or capacities exceed a 32-bit integer | Use a suitable wider type and validate additions for the expected input range |
| Per-edge flow looks wrong with antiparallel edges | A single residual matrix stores net adjustment, not separate edge identities | Use indexed residual-edge objects with explicit reverse indices when individual parallel or antiparallel flows must be reported |
| Runtime varies across runs | DFS path order depends on hash iteration | Use ordered adjacency for reproducible traces; the maximum value remains the same when the method terminates |
Never Omit the Reverse Update
After augmenting $u\to v$ by $\Delta$, perform both $c_f(u,v)-=\Delta$ and $c_f(v,u)+=\Delta$. The second line is not an optimization; it is what lets the method repair earlier path choices and is essential to correctness.
Exercises
Build the Intuition in Layers
- Trace: Re-run the worked example in a different augmenting-path order. Record every residual change and confirm the final value remains 5.
- Conserve: For the final SVG, verify capacity constraints and flow conservation vertex by vertex.
- Explain: Construct a network where a reverse residual edge is necessary to escape an earlier bad path choice.
- Certify: Modify the example capacities so $A\to B$ has capacity 0. Find a maximum flow and a minimum cut with the same value.
- Compare: Replace the DFS stack with a BFS queue. Count augmentations and edge scans on the same random integral networks.
- Engineer: Replace the residual matrix with indexed edge objects so parallel and antiparallel edges retain separate flow values.
A compact mental model
Ford–Fulkerson repeatedly improves a feasible solution in a graph of reversible choices. Forward residual capacity says “you may send more”; reverse residual capacity says “you may reconsider.” When the source can no longer reach the sink, the boundary of what remains reachable becomes a minimum-cut certificate that the flow is maximum.