A Bit of History
In 1972, Jack Edmonds and Richard Karp published a polynomial analysis of the shortest-augmenting-path rule for network flow. Yefim Dinitz had independently published the same shortest-path idea in 1970 as part of work that also led to the faster blocking-flow algorithm now associated with his name. The important algorithmic lesson is timeless: a small change in selection order can transform a correct method with an unstable runtime into one with a graph-size guarantee.
From Ford–Fulkerson to Edmonds–Karp
Both methods maintain exactly the same residual network and perform exactly the same augmentation update. Only the path-selection rule changes.
Residual capacities
Forward residual capacity permits more flow; reverse residual capacity permits cancelling earlier flow.
Push the bottleneck
For path $P$, push $\Delta=\min_{(u,v)\in P}c_f(u,v)$ and update both directions.
Choose with BFS
Among all residual $s$–$t$ paths, use one with the fewest edges.
“Shortest” Means Edge Count
BFS does not maximize the bottleneck, minimize capacity, or minimize a monetary cost. Every positive residual edge counts as one step, regardless of whether its residual capacity is 1 or one billion.
Working Principle
- Initialize the residual graph with the original capacities and zero-capacity reverse edges.
- Run BFS from $s$, traversing only edges whose residual capacity is positive.
- If BFS cannot reach $t$, stop: the current flow is maximum.
- Use the BFS parent map to reconstruct a shortest residual path from $s$ to $t$.
- Compute its bottleneck $\Delta$.
- Subtract $\Delta$ from each forward residual edge, add $\Delta$ to its reverse edge, and increase the flow value.
- Discard the old BFS labels and repeat on the updated residual graph.
The labels must be recomputed after every augmentation because residual edges can disappear or appear. What survives across rounds is not a particular BFS tree, but a monotonicity property of the shortest distances.
Reading the BFS Layers
BFS explores the residual graph in layers: distance 0, then 1, then 2, and so on. The first time it discovers the sink, its parent chain contains the fewest possible residual edges.
Worked Example
Use capacities $S\to A=3$, $S\to B=2$, $A\to T=2$, $B\to T=3$, and $A\to B=1$. Assume BFS considers A before B when both are discovered in the same layer.
What tie-breaking changes
If several shortest residual paths exist, BFS may return any of them. Neighbor order can change the exact augmentation trace, but not the $O(VE^2)$ guarantee or the final maximum value.
Why BFS Bounds the Iteration Count
Max-flow correctness still comes from Ford–Fulkerson: if no residual $s$–$t$ path exists, the vertices reachable from $s$ define a cut whose capacity equals the current feasible flow. BFS is needed for the runtime guarantee.
Lemma 1: residual distances never decrease
Let $d_f(v)$ be the fewest residual edges from $s$ to $v$ before an augmentation. New residual edges can appear only as reverses of edges just used on a shortest path. If $u\to v$ was on that path, then $d_f(v)=d_f(u)+1$; the new reverse $v\to u$ points from a later layer to an earlier one. It cannot create a shortcut from $s$. After the update, every reachable vertex therefore has the same or a larger BFS distance.
Lemma 2: one directed edge can be critical only $O(V)$ times
Every augmentation saturates at least one edge on its shortest path; call it critical. Before the same directed edge $u\to v$ can become critical again, some later path must use the reverse direction and restore its residual capacity. The BFS-layer relationships then force $d_f(u)$ to increase by at least 2. Distances are at most $V-1$, so each directed edge can be critical only $O(V)$ times.
There are $O(E)$ residual edge directions. Charging every augmentation to one saturated critical edge gives at most $O(VE)$ augmentations.
Complexity Analysis
With adjacency lists, one BFS scans $O(V+E)=O(E)$ work on the usual connected flow-network representation. Path reconstruction and residual updates take $O(V)$, which is covered by that bound. Combining it with at most $O(VE)$ augmentations gives:
$$\text{Time: } O(VE^2) \qquad \text{Space: } O(V+E)$$
| Property | Ford–Fulkerson with arbitrary paths | Edmonds–Karp |
|---|---|---|
| Path choice | Unspecified | BFS fewest-edge path |
| Integer-capacity bound | $O(EF)$ | $O(VE^2)$ |
| Depends on capacity magnitudes? | Yes | No |
| Irrational capacities | Arbitrary choices may not terminate | Terminates within the augmentation bound |
The guarantee is strongly polynomial: the number of arithmetic operations depends on $V$ and $E$, not on the numeric sizes of the capacities.
Implementation
These versions accept nonnegative integer capacities, build a private residual graph, and aggregate repeated directed edges where the input format permits them. Each returns an augmentation trace plus the source side of a minimum cut. That extra information turns the code into a teaching and debugging tool.
| State | Meaning | Invariant |
|---|---|---|
residual[u][v] | Additional net flow allowed from $u$ to $v$ | Traversed only when positive |
parent[v] | Vertex that first discovered $v$ in the current BFS | Its chain has the fewest residual edges |
delta | Minimum residual capacity on the chosen path | At least one path edge is saturated |
source_side | Vertices reachable after the final unsuccessful BFS | Defines a minimum cut |
Real-World Applications
Edmonds–Karp solves the same max-flow models as other maximum-flow algorithms. Its particular strengths are simple code, deterministic layer-based reasoning, and a capacity-independent guarantee—valuable when clarity and auditability matter more than leading performance.
Network bottleneck analysis
Model routers or facilities as vertices and link limits as capacities. The maximum value measures throughput; the final residual reachability exposes a minimum cut.
Bipartite assignment
Unit-capacity edges turn an integral maximum flow into a matching. The augmenting trace makes each reassignment visible through reverse edges.
Edge-disjoint paths
Set every edge capacity to 1. The maximum flow value equals the largest number of edge-disjoint source-to-sink routes.
Reference implementations
Because the algorithm is compact and predictable, it is useful as a correctness oracle for testing more sophisticated max-flow code on small and medium instances.
Model boundaries
Basic max flow treats the transferred units as interchangeable and optimizes only quantity. Costs require minimum-cost flow; lower bounds require a circulation reduction; multiple commodities sharing edges form a harder model. A polynomial algorithm does not repair a mismatched model.
Choosing a Flow Algorithm
| Method | Core rule | General bound | Use it when |
|---|---|---|---|
| Ford–Fulkerson | Any augmenting path | $O(EF)$ for integer capacities | The instance is small and integral, or the method itself is the lesson |
| Edmonds–Karp | One BFS path per augmentation | $O(VE^2)$ | You want straightforward code and predictable behavior |
| Dinic | One BFS level graph, then a blocking flow | $O(V^2E)$ | The network is larger and sparse |
| Push–relabel | Move local excess instead of finding full paths | $O(V^3)$ for a basic version | Dense or high-performance workloads justify more machinery |
Pitfalls & Debugging
| Symptom | Likely cause | Fix |
|---|---|---|
| A path is not actually shortest | A stack, priority queue, or weighted distance replaced the FIFO queue | Use a true FIFO queue and mark a vertex when it is first enqueued |
| The answer is too small | Reverse residual edges are missing from adjacency | Add both directions to adjacency even when reverse capacity starts at 0 |
| A later BFS uses stale information | Parent or visited state was reused after an augmentation | Create a fresh BFS parent map for every residual graph |
| The loop fails for $s=t$ | The empty path has no finite bottleneck | Reject or explicitly define this input before searching |
| Results overflow | Capacities or the total exceed the numeric type | Use a suitably wide type and validate the expected range |
| The trace differs but the value matches | Several shortest paths exist and neighbor order changed | Use ordered adjacency for reproducibility; different valid ties are not an error |
Rebuild BFS State Every Round
Residual capacities change after every push. An edge may vanish, and a reverse edge may appear. Reusing the previous parent tree can produce a non-residual path and destroys both correctness and the shortest-path guarantee.
Exercises
Build the Intuition in Layers
- Trace: Re-run the worked example with B visited before A. Record which shortest path changes and which quantities do not.
- Distinguish: Construct a graph where the fewest-edge augmenting path has a smaller bottleneck than a longer path.
- Prove: Fill in the contradiction showing why a new reverse residual edge cannot decrease a BFS distance.
- Measure: Instrument BFS edge scans, augmentation count, path length, and bottleneck. Compare against DFS Ford–Fulkerson on adversarial path orders.
- Certify: For random graphs, compute the capacity of the returned source-side cut and assert that it equals the reported flow value.
- Extend: Preserve one BFS level graph and find more than one compatible path before rebuilding it—the first conceptual step toward Dinic.
A compact mental model
Edmonds–Karp is disciplined Ford–Fulkerson. Residual edges keep choices reversible; BFS organizes those choices into layers; the bottleneck update improves the feasible flow; and the fact that layer distances never retreat limits how often the same edges can cause work.