Skip to main content

Network Flow

Introduction

Many optimization problems reduce to routing as much "stuff" as possible through a network subject to capacity limits, such as traffic through roads, data through pipes, and goods through supply chains. Network flow formalizes this and gives efficient algorithms with broad applications (e.g. bipartite matching).

The central problem: given a directed graph with edge capacities, a source and sink node, find the maximum amount of flow that can be routed from source to sink without violating any capacity or conservation constraints.

Definitions

Flow Network. A flow network is a directed graph G=(V,E)G = (V, E) where each edge eEe \in E has capacity ce0c_e \ge 0, a source node sVs \in V and sink node tVt \in V. We assume no edge enters ss and no edge leaves tt.

Flow. A flow is a function f:ER0f: E \rightarrow \mathbb{R}_{\ge 0} satisfiying the following two conditions:

  • Capacity constraint. For every edge eEe \in E: f(e)cef(e) \le c_e.
  • Conservation constraint. For every node vV{s,t}v \in V \setminus \{s, t\}:
e into vf(e)=e out of vf(e)\begin{align*} \sum_{e \text{ into } v} f(e) = \sum_{e \text{ out of } v} f(e) \end{align*}

That is, the flow in equals flow out at every internal node.

Value of a flow. The value of a flow is the total flow leaving the source:

value(f)=e out of sf(e)\begin{align*} \text{value}(f)= \sum_{e \text{ out of } s} f(e) \end{align*}

Maximum flow problem. Given a flow network (G,c,s,t)(G, c, s, t), find a flow ff maximizing f|f|.

Residual graph. Given a flow ff, the residual graph Gf=(V,Ef)G_f = (V, E_f) captures remaining capacity. For each edge (u,v)E(u, v) \in E.

  • Add a forward edge (u,v)(u, v) with residual capacity cefec_e - f_e if e=(v,w)e = (v, w) and fe<cef_e < c_e.
  • Add a backwards edge (v,u)(v, u) with residual capacity fef_e if if e=(v,w)e = (v, w) and fe>0f_e > 0.

These backward edges allow us to "cancel" or undo any previously routed flow.

Augmenting path. An augmenting path is any path from ss to tt in the residual graph GfG_f. We say the bottleneck capacity of path PP is:

bottleneck(P)=min(minforward eP(cefe),minbackward ePfe).\begin{align*} \text{bottleneck}(P) = \min( \min_{\text{forward } e \in P} (c_e - f_e), \min_{\text{backward } e \in P} f_e). \end{align*}

In other words, it is the maximum flow we can add/subtract onto any foward/backward edge along PP without violating any capacity constraints (without exceed cec_e or going below 0).

Ford-Fulkerson

Ford-Fulkerson repeatedly finds an augmenting path in the residual graph GfG_f and pushes flow along it equal to its bottleneck capacity, until no augmenting path remains. After finding an augmenting path PP with flow ff and bottleneck bb, we use the following augment operation.

  • For each forward edge ePe \in P: set f(e)f(e)+bf(e) \leftarrow f(e) + b.
  • For each backward edge ePe \in P (reversing an original edge eEe' \in E): set f(e)f(e)bf(e') \leftarrow f(e') - b.

Algorithm

Ford-Fulkerson(G, s, t, c):
f(e) = 0 for all edges
build residual graph G_f
while there is an s-t path P in G_f:
b = bottleneck(P)
f = augment(f, P, b)
update G_f
return flow f

Lemma: Augmenting preserves capacity and conservation constraints.

Let ff be a valid flow, PP be a simple sts-t path in GfG_f and b=bottleneck(P)>0b = \text{bottleneck}(P) > 0. Let ff' be the flow after augmenting ff with path PP.

Recall that the augment performs the following operation to forward/backward edges:

  • Forward edge (u,v)(u, v) with e=(u,v)Ee = (u, v) \in E with fe<cef_e < c_e; we set f(e)=f(e)+bf'(e) = f(e) + b.
  • Backward edge (u,v)(u, v) with e=(v,e)Ee = (v, e) \in E with fe>0f_e > 0; we set f(e)=f(e)bf'(e) = f(e) - b.

For our bottleneck b>0b > 0,

  • bcefeb \le c_e - f_e for every forward edge ee.
  • bfeb \le f_e for every backward edge ee.

We show the capacity constraint, i.e. 0f(e)ce0 \le f'(e) \le c_e for every eEe \in E.

Case 1: ePe \notin P. This means that the edge ee was not augmented, so f(e)=f(e)f'(e) = f(e). Because ff is a valid flow, we have 0f(e)=f(e)ce0 \le f(e) = f'(e) \le c_e as required.

Case 2: ePe \in P, ee is used as a forward edge. Then, f(e)=f(e)+bf'(e) = f(e) + b. We have:

f(e)=f(e)+b0+0>0f(e)=f(e)+bf(e)+(cef(e))=ce\begin{align*} f'(e) &= f(e) + b \ge 0 + 0 > 0 \\ f'(e) &= f(e) + b \le f(e) + (c_e - f(e)) = c_e \end{align*}

where the upperbound uses bcef(e)b \le c_e - f(e).

Case 3: ePe \in P, ee is used as a backward edge. Then, f(e)=f(e)bf'(e) = f(e) - b.

f(e)=f(e)bf(e)f(e)=0f(e)=f(e)bf(e)ce\begin{align*} f'(e) &= f(e) - b \ge f(e) - f(e) = 0 \\ f'(e) &= f(e) - b \le f(e) \le c_e \end{align*}

The lower bound uses bf(e)b \le f(e), and the upper bound uses b>0b > 0.

In all cases 0f(e)ce0 \le f'(e) \le c_e, so ff' satisfies the capacity constraint.

Next, we show that the conservation constraint is satisfied.

We fix an internal node vV{s,t}v \in V \setminus \{s, t\}. Since ff satisfies conservation at vv, it is enough to show the augmentation changes the total inflow and outflow at vv by the same amount. We denote these changes as δin(v)\delta_{in}(v) and δout(v)\delta_{out}(v).

If vPv \notin P, no incident edge to vv is modified, so δin(v)=δout(v)=0\delta_{in}(v) = \delta_{out}(v) = 0 and conservation is preserved.

Otherwise, vv is an interval vertex of our path PP, so there is exactly one incoming edge (u,v)(u, v) and one outgoing edge (v,w)(v, w) in GfG_f. Each contributes ±b\pm b to the flow on its underlying original edge.

Consider the case where (u,v)(u, v) is a forward edge and (v,w)(v, w) is a backward edge.

  • Since (u,v)(u, v) is a forward edge, we contribute +b+ b to δin(v)\delta_{in}(v).
  • Since (v,w)(v, w) is a backward edge (original edge is (w,v)(w, v)), we contribute b- b to δin(v)\delta_{in}(v).

In total, we contribute b+(b)=0b + (- b) = 0 to δin(v)\delta_{in}(v) and leave δout(v)\delta_{out}(v) unchanged. In this case, δin(v)=δout(v)\delta_{in}(v) = \delta_{out}(v), so conservation is preserved. As an exercise, extend this reasoning to the rest of the cases:

  • (u,v)(u, v) is a forward edge and (v,w)(v, w) is a forward edge.
  • (u,v)(u, v) is a backward edge and (v,w)(v, w) is a forward edge.
  • (u,v)(u, v) is a backward edge and (v,w)(v, w) is a backward edge.

Thus, in every case δin(v)=δout(v)\delta_{in}(v) = \delta_{out}(v). Since e into vf(e)=e out of vf(e)\sum_{e \text{ into } v} f(e) = \sum_{e \text{ out of } v} f(e) held for ff, adding equal changes to both sides preserves the equality for ff'. As vv was an arbitrary internal node, ff' satisfies conservation everywhere.

Together, these establish that ff' is a valid flow.

Termination. If all ceZc_e \in \mathbb{Z}, then every residual capacity stays integral, so each bottleneck is a positive integer and value increase by at least 1 per iteration. Since value(f)C:=eout of sce(f) \le C := \sum_{e \text{out of } s} c_e, the loop runs at most CC times.

Runtime Analysis. Suppose for flow network graph G=(V,E)G = (V, E), let m=Em = |E|. We can find augmenting paths in O(m)O(m) time and augments in O(n)O(n) time (each path has at most nn nodes). This gives O(mC)O(mC) time overall, since the loop can run at most CC times. This is only pseudo-polynomial: the runtime depends on the capacities, not just on nn and mm.

Since the algorithm doesn't specify which augmenting path to pick at each step, a poor choice of paths can be extremely slow. Consider a network where an internal edge has capacity 1 but every other edge has a much larger capacity CC. If Ford-Fulkerson happens to alternate between two augmenting paths that both route through this narrow edge, forward through it in one path and backward (canceling flow) in the next, each round trip only increases the total flow by 1, even though a smarter choice of paths would saturate the network in just two augmentations.

Ford-Fulkerson bad instanceA flow network on nodes s, a, b, and t where s-a, s-b, a-t, and b-t all have capacity 1000, but the internal edge a-b has capacity 1.10001000110001000sabt
Every edge has capacity 1000 except a‑b, whose capacity is 1. An unlucky sequence of augmenting paths that keeps crossing a‑b (forward, then backward to cancel it) makes Ford-Fulkerson take 2000 iterations, even though the max flow of 2000 could be reached in just 2.

Visualization Demo

Ford-Fulkerson Visualizer

Start with zero flow

Every edge begins at 0 flow.

Total flow0
0/20/10/20/20/1sabt

Properties

Applications

Bipartite Matching

Max-flow Reduction

Min-cut Reduction

Practice

Problem 1.