Menger Theorem and Network Flows
Menger's theorem and max-flow min-cut are two versions of the same principle: the maximum number of independent ways to move through a network equals the minimum size of a bottleneck that blocks all movement. This is one of the clearest places where graph theory turns a routing question into a structural equality.
Network flows add capacities to directed edges. Instead of asking only whether a path exists, we ask how much material can be sent from a source to a sink while respecting capacity constraints. The algorithmic picture is built from augmenting paths, residual networks, and cuts.
Definitions
An - path is a path from source to target . Two paths are edge-disjoint if they share no edges, and internally vertex-disjoint if they share no vertices except possibly and .
An - edge cut is a set of edges whose deletion separates from . An - vertex cut is a set of vertices, excluding and , whose deletion separates from .
A flow network is a directed graph with source , sink , and capacities on arcs. A flow satisfies:
- Capacity constraints: .
- Flow conservation at every vertex except : inflow equals outflow.
The value of the flow is the net amount leaving .
The residual capacity of a forward arc is , and the residual capacity of a backward arc is .
Key results
Menger's edge theorem. For distinct vertices in a finite graph, the maximum number of pairwise edge-disjoint - paths equals the minimum size of an - edge cut.
Menger's vertex theorem. For nonadjacent , the maximum number of pairwise internally vertex-disjoint - paths equals the minimum size of an - vertex cut.
Max-flow min-cut theorem. In a finite flow network, the maximum value of an - flow equals the minimum capacity of an - cut.
Integrality theorem. If all capacities are integers, then there is a maximum flow whose arc values are all integers.
These theorems explain why unit-capacity flow can prove Menger-type path-packing results.
Residual networks. A residual network records what changes are still possible. A forward residual edge means extra flow can be sent along an arc. A backward residual edge means existing flow can be cancelled and rerouted. This is why augmenting-path algorithms can recover from an early poor choice: they are not simply adding more flow, they are adjusting the current flow inside the feasible region.
Cuts as certificates. A flow proves a lower bound on the maximum value. A cut proves an upper bound, because every unit of flow from to must cross from the source side of the cut to the sink side. When a flow value equals a cut capacity, both are optimal. This dual certificate pattern is one of the most important habits in network optimization.
Vertex-disjoint paths by splitting vertices. To model internally vertex-disjoint paths as a flow problem, replace each vertex other than by two vertices and joined by an arc of capacity . Original incoming edges enter , and original outgoing edges leave . This forces at most one unit of flow through each internal vertex.
Edge connectivity and vertex connectivity. The edge version of Menger's theorem leads to edge connectivity: the minimum number of edges whose removal disconnects the graph. The vertex version leads to vertex connectivity: the minimum number of vertices whose removal disconnects the graph or reduces it to a trivial graph. These parameters measure different kinds of robustness. A network can have high edge connectivity but low vertex connectivity if many routes pass through the same articulation point.
Ford-Fulkerson termination. With integer capacities, each augmenting path increases the flow value by at least , so the basic Ford-Fulkerson method terminates. With irrational capacities and careless path choices, termination can fail. Edmonds-Karp avoids this issue by always choosing a shortest augmenting path in the residual network and has a polynomial time bound.
Visual
| Cut containing | Crossing arcs to | Capacity |
|---|---|---|
Worked example 1: Compute a maximum flow
Problem. In the network above, find a maximum - flow.
Method.
Capacities are:
Use augmenting paths.
- Send units along . This saturates .
Flow value: .
- Send units along . This saturates .
Flow value: .
- There is still residual capacity on , on , and on . Send unit along
Flow value: .
The final nonzero flows are:
Cut check. The cut has capacity . Since we found a flow of value and a cut of capacity , max-flow min-cut proves optimality.
Checked answer. The maximum flow value is .
Worked example 2: Edge-disjoint paths via unit capacities
Problem. In an undirected graph with edges
find the maximum number of edge-disjoint - paths.
Method.
- Exhibit three paths:
This list is not edge-disjoint because is used in the first and third paths.
- Try again:
Now uses , and uses . They are edge-disjoint.
- Can there be a third? The source has degree , with incident edges and . Every - path must use one of these two edges when leaving .
- Therefore any collection of edge-disjoint - paths has size at most .
Checked answer. The maximum number of edge-disjoint - paths is , equal to the minimum edge cut .
This is exactly the unit-capacity form of max-flow min-cut. Give every undirected edge capacity in both directions, or orient each edge both ways with shared-capacity care in a more formal model. The degree of supplies a cut of capacity , and the two displayed paths supply a flow of value .
Code
Edmonds-Karp is the breadth-first-search version of Ford-Fulkerson.
from collections import deque, defaultdict
def max_flow(capacity, source, sink):
residual = defaultdict(dict)
for u, nbrs in capacity.items():
for v, c in nbrs.items():
residual[u][v] = c
residual[v].setdefault(u, 0)
flow_value = 0
while True:
parent = {source: None}
q = deque([source])
while q and sink not in parent:
u = q.popleft()
for v, c in residual[u].items():
if c > 0 and v not in parent:
parent[v] = u
q.append(v)
if sink not in parent:
break
bottleneck = float("inf")
v = sink
while v != source:
u = parent[v]
bottleneck = min(bottleneck, residual[u][v])
v = u
v = sink
while v != source:
u = parent[v]
residual[u][v] -= bottleneck
residual[v][u] += bottleneck
v = u
flow_value += bottleneck
return flow_value
capacity = {"s": {"a": 3, "b": 2}, "a": {"b": 1, "t": 2}, "b": {"t": 3}, "t": {}}
print(max_flow(capacity, "s", "t"))
The returned number is only the flow value. A production implementation would also return the final arc flows and the minimum cut obtained from vertices reachable from in the final residual network. Returning both objects gives the lower-bound and upper-bound certificates side by side.
In worked flow problems, always finish by naming a cut with the same value as the proposed flow. The cut is what proves that no hidden augmenting route can do better. Without it, a large flow is only a candidate solution.
In flow computations, separate feasibility from optimality. Feasibility means capacities and conservation hold. Optimality means no larger flow exists, usually certified by a cut of equal value. Many arithmetic mistakes produce flows that look large but violate conservation at an intermediate vertex. Check conservation before looking for the final cut certificate.
Common pitfalls
- Confusing edge-disjoint and vertex-disjoint paths.
- Allowing an - vertex cut to include or in the standard form of Menger's theorem.
- Forgetting backward arcs in a residual network. They represent the ability to reroute existing flow.
- Assuming a greedy first augmenting path always gives the final flow. It may need later correction through residual edges.
- Comparing flow value to the wrong cut direction. An - cut counts arcs from the source side to the sink side.
- Treating capacities as edge weights for shortest paths. Flow capacities limit throughput; they are not distances.