Summary

Maximum flow problem on directed graphs: find the most flow from source to sink respecting edge capacities. Connects to minimum cuts via the max-flow min-cut theorem (𝐹=𝑐(𝑆) for the optimal s-t cut).


We are dealing with directed graphs 𝐺(𝑉,𝐸) with a source vertex 𝑠 and a sink vertex 𝑡. Each edge has a capacity 𝑐:𝐸0, and we define 𝑐(𝑢,𝑣)=0 if (𝑢,𝑣)𝐸. When drawing a graph, we write 23 on an edge to mean “currently flowing 2 out of a max capacity of 3.” The goal is to push as much flow as possible from 𝑠 to 𝑡.

Net Flow

A net flow is a function 𝑓:𝑉×𝑉 that assigns a real number to every pair of vertices. This value can be negative: if 𝑓(𝑢,𝑣)<0, it means there is flow of |𝑓(𝑢,𝑣)| going from 𝑣 to 𝑢 instead.

The value of a flow is |𝑓|=𝑣𝑓(𝑠,𝑣) (the total flow leaving the source).

Flow Constraints

Every valid flow must satisfy three rules:

  1. Feasibility: 𝑓(𝑢,𝑣)𝑐(𝑢,𝑣)𝑢,𝑣𝑉 (you can’t exceed the capacity of an edge)
  2. Conservation: 𝑢𝑓(𝑢,𝑣)=0𝑣𝑉{𝑠,𝑡} (at every vertex except 𝑠 and 𝑡, flow in equals flow out)
  3. Skew symmetry: 𝑓(𝑢,𝑣)=𝑓(𝑣,𝑢) (flow from 𝑢 to 𝑣 is the negative of flow from 𝑣 to 𝑢)

Lemma (Flow Decomposition)

Let supp𝑓(𝐺) be the subgraph of 𝐺 containing only edges (𝑢,𝑣) where 𝑓(𝑢,𝑣)>0. This support graph can be decomposed into a collection of 𝑠-𝑡 flow paths and flow cycles.

Checking 𝐹>0

To check whether the max flow 𝐹=|𝑓| is positive, just check if there exists any 𝑠-𝑡 path in 𝐺 (ignoring zero-capacity edges). If such a path exists, 𝐹>0.

Let ̂𝑆={𝑣𝑉:𝑠-𝑣path in𝐺} (the set of vertices reachable from 𝑠). We know 𝑠̂𝑆, and if 𝐹=0 then 𝑡̂𝑆 (the sink is unreachable).

s-t Cut

An s-t cut is a partition of the vertices into two sets (𝑆,𝑉𝑆) such that 𝑠𝑆 and 𝑡𝑉𝑆.

The capacity of a cut is the total capacity of edges crossing from 𝑆 to 𝑉𝑆:

𝑐(𝑆)=𝑐(𝑆,𝑉𝑆)=𝑢𝑆𝑣𝑉𝑆𝑐(𝑢,𝑣)

Only edges going from 𝑆 to 𝑉𝑆 count, not edges going back.

Key Equivalence

𝐹=0path from𝑠to𝑡in𝐺s-t cut𝑆with𝑐(𝑆)=0

Minimum s-t Cut Problem

We want to find an s-t cut in 𝐺(𝑉,𝐸,𝑠,𝑡,𝑐) with minimum capacity. The net flow across a cut is:

𝑓(𝑆)=𝑓(𝑆,𝑉𝑆)=𝑢𝑆𝑣𝑉𝑆𝑓(𝑢,𝑣)

This sums all the positive flow leaving 𝑆 and subtracts everything flowing back into 𝑆. By feasibility, 𝑓(𝑆)𝑐(𝑆) (the net flow across any cut can’t exceed the cut’s capacity).

Claim: Flow Across Any Cut Equals |𝑓|

For any two s-t cuts 𝑆 and 𝑆, we have 𝑓(𝑆)=𝑓(𝑆). The intuition is:

  • A cycle staying entirely within one side of the cut contributes nothing (it never crosses).
  • A cycle crossing the cut has net contribution 0 (it leaves and comes back).
  • An 𝑠-𝑡 path crosses the cut exactly once more in the forward direction than backward.

Since |𝑓|=𝑓({𝑠}) (the flow value is the net flow out of 𝑠 alone), this means |𝑓|=𝑓(𝑆) for any s-t cut 𝑆.

Weak Duality

For any flow 𝑓 and any s-t cut 𝑆:

|𝑓|=𝑓(𝑆)𝑐(𝑆)

In particular, 𝐹𝑐(𝑆) for every s-t cut. The maximum flow value can never exceed the capacity of any cut.

Max Flow Problem

A naive approach is to start with zero flow, find an 𝑠-𝑡 path with positive capacity, and push flow along it. That sounds reasonable, but it can get stuck because an early choice may block a better routing later. The fix is to let ourselves undo earlier choices when needed, which is exactly what residual networks do.

If you want one sentence to remember: max flow is not just “keep adding flow,” it is “keep adding flow while preserving the option to reroute it later.”

Residual Networks

Residual Network

Given a flow 𝑓 in 𝐺, the residual network 𝐺𝑓=(𝑉,𝐸𝑓,𝑠,𝑡,𝑐𝑓) has residual capacities:

𝑐𝑓(𝑢,𝑣)=𝑐(𝑢,𝑣)𝑓(𝑢,𝑣)

This tells us how much additional flow we can push along each edge. An edge (𝑢,𝑣)𝐸𝑓 if and only if 𝑐𝑓(𝑢,𝑣)>0.

Why Reverse Edges Appear

Residual networks automatically include reverse edges that let us “undo” flow. If we’re currently sending 𝑓(𝑢,𝑣)>0 flow from 𝑢 to 𝑣, then by skew symmetry 𝑓(𝑣,𝑢)=𝑓(𝑢,𝑣), so:

𝑐𝑓(𝑣,𝑢)=𝑐(𝑣,𝑢)𝑓(𝑣,𝑢)=𝑐(𝑣,𝑢)+𝑓(𝑢,𝑣)>0

This means (𝑣,𝑢)𝐸𝑓 even if there was no original edge from 𝑣 to 𝑢. Pushing flow along this reverse edge effectively cancels some of the flow we previously sent from 𝑢 to 𝑣.

By feasibility, residual capacities satisfy 0𝑐𝑓(𝑢,𝑣)𝑐(𝑢,𝑣)+𝑐(𝑣,𝑢).

Lemma (Flow Composition)

If 𝑓 is a valid flow in 𝐺 and 𝑓 is a valid flow in 𝐺𝑓, then 𝑓+𝑓 is a valid flow in 𝐺 with value |𝑓|+|𝑓|.

Augmenting Paths

To improve a flow 𝑓, find an 𝑠-𝑡 path 𝑃 in the residual network 𝐺𝑓. This is called an augmenting path. Push flow along 𝑃 up to its bottleneck (the smallest residual capacity along the path):

𝑐𝑓(𝑃)=min(𝑢,𝑣)𝑃𝑐𝑓(𝑢,𝑣)

Ford-Fulkerson Algorithm

Ford-Fulkerson

  1. Start with zero flow 𝑓=0.
  2. Build the residual network 𝐺𝑓.
  3. Find an augmenting path 𝑃 in 𝐺𝑓.
  4. Push 𝑐𝑓(𝑃) units of flow along 𝑃 (updating 𝑓).
  5. Repeat from step 2 until no augmenting path exists.

Each iteration takes 𝑂(𝑚) time (finding a path and updating). The number of augmentations is at most 𝐹𝑛𝐶 where 𝐶=max𝑒𝑐(𝑒), giving total runtime 𝑂(𝑚𝑛𝐶). This is pseudopolynomial: polynomial in the value of 𝐶, not in the number of bits needed to represent 𝐶.

Strong Duality (Max-Flow Min-Cut Theorem)

When Ford-Fulkerson terminates (no augmenting paths remain), the flow is optimal. Here is why:

If there are no augmenting paths, there is no 𝑠-𝑡 path in 𝐺𝑓. Define ̂𝑆={𝑣𝑉|𝑣reachable from𝑠in𝐺𝑓}. Since 𝑡̂𝑆, this is a valid s-t cut. For every edge crossing the cut, 𝑐𝑓(𝑢,𝑣)=0 for 𝑢̂𝑆,𝑣̂𝑆, meaning 𝑐𝑓(̂𝑆)=0. Expanding:

𝑐𝑓(𝑆)=𝑢𝑆𝑣𝑉𝑆(𝑐(𝑢,𝑣)𝑓(𝑢,𝑣))=𝑐(𝑆)𝑓(𝑆)

Setting 𝑐𝑓(̂𝑆)=0 gives 𝑐(̂𝑆)=𝑓(̂𝑆)=|𝑓|. Combined with weak duality:

|𝑓|𝐹𝑐(𝑆)𝑐(̂𝑆)=|𝑓||𝑓|=𝐹

The maximum flow value equals the minimum cut capacity.

Theorem (Max-Flow Min-Cut)

The following are equivalent:

  1. |𝑓|=𝑐(𝑆) for some s-t cut 𝑆.
  2. 𝑓 is a maximum flow.
  3. 𝑓 admits no augmenting path in 𝐺𝑓.

Theorem (Flow Integrality)

If all capacities are integers, then 𝐹 is an integer and there exists a max flow 𝑓 where every edge carries integer flow. Ford-Fulkerson will find such a flow.

There are cases where Ford-Fulkerson can take a very long time, namely when capacities are large relative to the graph size. The pseudopolynomial runtime means it’s fine for small-capacity networks but can be exponentially slow when 𝐶 is encoded in binary (e.g., 𝐶=2𝑛).

Maximum Bottleneck Path Algorithm (MBP)

Instead of picking any augmenting path, we choose the path 𝑃 in each iteration that maximizes the residual bottleneck capacity 𝑐𝑓(𝑃). This path can be found in 𝑂(𝑚log𝑛) time.

Claim

In any graph 𝐺, there exists an 𝑠-𝑡 path 𝑃 with

𝑐(𝑃)=min𝑒𝑃𝑐(𝑒)𝐹𝑚

To see why: by the flow decomposition lemma, the max flow 𝑓 decomposes into at most 𝑚 flow paths and cycles. The entire value 𝐹 is carried by at most 𝑚 paths. By averaging, at least one path must carry 𝐹𝑚 flow, so its bottleneck capacity is at least 𝐹𝑚.

MBP Runtime: 𝑂(𝑚2log𝑛log(𝑛𝐶))

Let 𝐹𝑗 be the remaining “missing” flow at the start of iteration 𝑗 (i.e., 𝐹𝑗=𝐹𝐹𝑗 where 𝐹𝑗 is the flow pushed so far). By our claim applied to the residual network, the bottleneck path pushes at least 𝐹𝑗𝑚 flow, so:

𝐹𝑗+1(11𝑚)𝐹𝑗(11𝑚)𝑗𝐹

After 𝑗=𝑚ln(𝐹) iterations: (11𝑚)𝑚ln(𝐹)𝐹<𝑒ln(𝐹)𝐹=1. By the integrality theorem, if 𝐹𝑗+1<1 then 𝐹𝑗+1=0, so the algorithm terminates.

Each iteration costs 𝑂(𝑚log𝑛), and we need at most 𝑚ln(𝑛𝐶) iterations, giving 𝑂(𝑚2log𝑛log(𝑛𝐶)) total. This is a weakly polynomial runtime (the dependence on the input numbers is only logarithmic).

Using BFS to find the shortest augmenting path gives the Edmonds-Karp algorithm with runtime 𝑂(𝑚2𝑛). The analysis is more involved, but the key idea is that shortest-path distances in 𝐺𝑓 can only increase over time, bounding the total number of augmentations to 𝑂(𝑚𝑛).

Bipartite Matching

A bipartite graph has two disjoint sets of vertices 𝐿 and 𝑅, where every edge goes between 𝐿 and 𝑅 (no edges within the same side). A matching is a subset of edges where no vertex appears more than once, i.e., every vertex is “used” at most once. The goal is to find a matching with the most edges possible (maximum cardinality). This is one of the most important applications of max flow: many assignment and scheduling problems reduce to bipartite matching.

A classic example: 𝐿 is a set of jobs and 𝑅 is a set of machines, with an edge (𝑗,𝑚) meaning machine 𝑚 can handle job 𝑗. We want to assign as many jobs as possible, but each machine can only do one job and each job only needs one machine.

Reduction to Max Flow

This problem reduces to maximum flow. Given a bipartite graph (𝐿,𝑅,𝐸):

  1. Direct all edges from 𝐿 to 𝑅, each with capacity 1.
  2. Add a source 𝑠 with a capacity-1 edge to every vertex in 𝐿.
  3. Add a sink 𝑡 with a capacity-1 edge from every vertex in 𝑅 to 𝑡.

Since all capacities are 1, the integrality theorem guarantees the max flow is integer-valued, meaning each edge either carries flow 0 or 1. The capacity-1 edges from 𝑠 ensure each vertex in 𝐿 sends flow to at most one neighbor, and the capacity-1 edges to 𝑡 ensure each vertex in 𝑅 receives from at most one neighbor. So any integer max flow corresponds to a valid matching, and vice versa.

Claim

The max flow value equals the size of the maximum matching: |𝑓|=|𝑀|.

Ford-Fulkerson on this network runs in 𝑂(𝑚𝑛) time: each augmentation takes 𝑂(𝑚) and pushes 1 unit of flow (since all capacities are 1), so there are at most |𝑀|𝑛2 augmentations.