This deck covers flow networks and the two rules a valid flow obeys, residual graphs and why augmenting paths need back edges, the Ford-Fulkerson and Edmonds-Karp algorithms, the max-flow min-cut theorem, and the reduction from bipartite matching. It targets four real misconceptions: exceeding an edge's capacity, forgetting the residual back edges, confusing the value of the max flow with the capacity of the min cut, and assuming that a single greedy highest-capacity path finishes the job. Every trace was verified by hand.
Subject: CS3000 Algorithms · 130 slides · symbolic lesson
Open the interactive version of this deck · Homework for this lesson
Title
CS3000 Algorithms
How much can flow through a network, and how do you prove you've found the most?
Objectives
By the end of this lesson you can:
Warm-up
Discussion prompt
Before we open Network Flow: Max-Flow Min-Cut: without looking back, what was the main idea of Minimum Spanning Trees: Prim & Kruskal, and what could you do by the end of it that you could not do before?
Hint: One sentence for the idea, one for the skill. If the second one is blank, that is the part to revisit.
Answer:
That deck explains what a minimum spanning tree is, then gives the cut property and the cycle property that make greedy MST algorithms provably correct. It includes full hand-traced runs of Prim's and Kruskal's algorithms, the latter with union-find, along with their running times. It targets the misconceptions that an MST is always unique, that it is the same thing as a shortest-path tree, that Kruskal never needs a cycle check, and that union-find stores weights or paths rather than connectivity alone.
Concept
Before any new material: cover the screen.
You have named 15 reusable moves so far. Say as many as you can out loud, by number, from memory.
Do not advance until you have actually tried. Getting four of eight is information; skipping the exercise is not.
Here they are. Score yourself.
Today adds one move to this list. Everything else you will need is already above.
The question that starts every proof from here on is not how do I begin. It is which of these applies here?
Counterexample
Discussion prompt
You have named 15 reusable moves so far. Say as many as you can out loud, by number, from memory.
That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.
Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.
Answer:
Do not advance until you have actually tried. Getting four of eight is information; skipping the exercise is not.
Section
Section 1
Picture it
Figure (svg): A flow network with four nodes s, a, b, t. Edges go from s to a, s to b, a to b, a to t, and b to t, each labeled capacity 1.
Discussion prompt
Read the picture before the words. What is this showing, and what is the one thing it is built to make obvious? Commit to an answer, then read on.
Hint: Name the parts, then say what changes between them — and if nothing changes, say what is being held still.
Answer:
A flow network is a directed graph built for one job: moving something from a single starting point to a single ending point.
Concept
A flow network is a directed graph built for one job: moving something from a single starting point to a single ending point.
source — The one node everything starts from, usually named s. Nothing flows into the source in a well-formed network.
sink — The one node everything ends up at, usually named t. Nothing flows out of the sink.
Every other node is an internal node: things pass through it, but nothing is created or destroyed there.
capacity — Every directed edge carries a capacity, the maximum amount that edge can carry. Write the capacity of the edge from u to v as c(u,v).
Figure (svg): A flow network with four nodes s, a, b, t. Edges go from s to a, s to b, a to b, a to t, and b to t, each labeled capacity 1.
This four-node network, s, a, b, t, will run through the whole lesson. Every edge here happens to have capacity 1, which keeps the arithmetic simple while the ideas stay real.
Definition probe
Sort into buckets
Every line below is part of the definition of source or of sink — one or the other, never both. Put each where it belongs.
Picture it
Animation
Shows: A flow network is a weighted digraph — a rendered Manim animation.
Rendered with Manim.
Takeaway: Weights are capacities — a ceiling on each pipe, not a cost.
Concept
An edge from s to a with capacity 1 says nothing about a direction from a back to s. If that reverse edge is not drawn in the network, its capacity is 0.
\[ c(s,a) = 1 \quad \text{but} \quad c(a,s) = 0 \ \text{(no such edge drawn)} \]
Keep this in mind. Later, the algorithm will invent a way to move flow backward along an edge, but that is a separate bookkeeping trick, not a claim that the original network secretly had a reverse edge with real capacity.
Analogy
Discussion prompt
Explain Capacities only run one way by analogy to something with no CS3000 Algorithms in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.
Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.
Answer:
An edge from s to a with capacity 1 says nothing about a direction from a back to s. If that reverse edge is not drawn in the network, its capacity is 0.
Intuition
Picture the network as pipes. Each directed edge is a pipe with a maximum flow rate, the capacity. Water pours in at the source and must come out at the sink.
A pipe can be running below its maximum, right at its maximum, or empty. What a pipe can never do is carry more water than its capacity allows, and water can never appear or vanish inside a pipe junction.
Explain it
Discussion prompt
Explain Pipes carrying water to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.
Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.
Answer:
Picture the network as pipes. Each directed edge is a pipe with a maximum flow rate, the capacity. Water pours in at the source and must come out at the sink.
Concept
A flow assigns a number to every edge, how much is currently moving through it. The first rule any valid flow must obey is the capacity constraint.
\[ 0 \le f(u,v) \le c(u,v) \quad \text{for every edge } (u,v) \]
The flow on an edge can be zero, it can equal the capacity exactly, or anything in between. It can never go negative and it can never go over.
Concept
The second rule is flow conservation: at every internal node (not the source, not the sink), the total flow arriving must exactly equal the total flow leaving.
flow conservation — For every internal node v, the sum of flow on edges coming in equals the sum of flow on edges going out. Nothing is stored or created at an internal node.
\[ \sum_{u} f(u,v) \;=\; \sum_{w} f(v,w) \quad \text{for every internal node } v \]
Only the source and the sink are allowed to have an imbalance. Everywhere else, whatever comes in during one instant must leave during that same instant.
Picture it
Figure (svg): The s, a, b, t network with flow labeled on each edge: s to a carries 1 of 1, a to t carries 1 of 1, s to b carries 1 of 1, b to t carries 1 of 1, and a to b carries 0 of 1.
Discussion prompt
Read the picture before the words. What is this showing, and what is the one thing it is built to make obvious? Commit to an answer, then read on.
Hint: Name the parts, then say what changes between them — and if nothing changes, say what is being held still.
Answer:
On the s, a, b, t network, check whether this assignment is a valid flow: 1 unit on s to a, 1 unit on a to t, 1 unit on s to b, 1 unit on b to t, and 0 on a to b.
Worked example
On the s, a, b, t network, check whether this assignment is a valid flow: 1 unit on s to a, 1 unit on a to t, 1 unit on s to b, 1 unit on b to t, and 0 on a to b.
Figure (svg): The s, a, b, t network with flow labeled on each edge: s to a carries 1 of 1, a to t carries 1 of 1, s to b carries 1 of 1, b to t carries 1 of 1, and a to b carries 0 of 1.
Check the capacity constraint on every edge
Why: Every listed flow value is either 0 or 1, and every capacity is 1. No edge carries more than it can hold, so rule one holds everywhere.
| edge | flow | capacity | within capacity |
|---|---|---|---|
| s to a | 1 | 1 | yes |
| s to b | 1 | 1 | yes |
| a to b | 0 | 1 | yes |
| a to t | 1 | 1 | yes |
| b to t | 1 | 1 | yes |
Check conservation at node a
Why: Flow into a is only from s to a, which is 1. Flow out of a is a to b (0) plus a to t (1), which totals 1. In equals out.
\[ \text{in}(a) = 1, \quad \text{out}(a) = 0 + 1 = 1 \]
Check conservation at node b
Why: Flow into b is s to b (1) plus a to b (0), totaling 1. Flow out of b is b to t, which is 1. In equals out again.
\[ \text{in}(b) = 1 + 0 = 1, \quad \text{out}(b) = 1 \]
Verify both rules hold at every internal node and edge
Why: Rule one held on all five edges, and rule two held at both internal nodes a and b. Nothing was checked at s or t because conservation is never required there. This is a valid flow.
Invariant
Step through it
Step through Verify a candidate flow is valid one row at a time. One of these columns never changes — find it, and say why it cannot.
Ranking
Put in order
Put the moves of Conservation with two incoming edges into the order they have to happen.
Why: These are the moves of the worked example in the order it makes them, and each one is set up by the one before it. Two separate edges deliver flow into c.
Worked example
Conservation has to balance every edge touching a node, not just one pair. Suppose node c has two edges coming in and a single edge going out.
| edge | direction | flow |
|---|---|---|
| x to c | in | 2 |
| y to c | in | 1 |
| c to z | out | 3 |
Add up everything arriving at c
Why: Two separate edges deliver flow into c. Conservation cares about the total arriving, not any single edge.
\[ \text{in}(c) = f(x,c) + f(y,c) = 2 + 1 = 3 \]
Compare to what leaves c
Why: Only one edge leaves c, carrying 3 units.
\[ \text{out}(c) = f(c,z) = 3 \]
Verify the node balances
Why: 3 arriving equals 3 leaving, so conservation holds at c even though the in-degree and out-degree are different. Conservation is about totals, not about matching the number of edges.
Picture it
Animation
Shows: Each line of the worked example "Conservation with two incoming edges", appearing one at a time.
The same working the example does, in the order a tutor would write it.
Takeaway: 3 arriving equals 3 leaving, so conservation holds at c even though the in-degree and out-degree are different. Conservation is about totals, not about matching the number of edges.
Anomaly
Predict first
A student writes this, and it looks reasonable:
A student wants more flow through the network fast, so they push 2 units across the edge from s to a, whose capacity is only 1.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: This directly breaks the capacity constraint: 2 is greater than the capacity 1.
An edge's capacity is a hard ceiling, not a suggestion. If more needs to move from s to a than one edge allows, it has to go by some other route entirely, using a different edge.
Why: This directly breaks the capacity constraint: 2 is greater than the capacity 1. This is not a flow with a strange property, it is not a flow at all, and every conclusion drawn from it is meaningless.
Trap
A student wants more flow through the network fast, so they push 2 units across the edge from s to a, whose capacity is only 1.
\[ c(s,a) = 1 \]
Assign f(s,a) = 2 anyway
Why: This directly breaks the capacity constraint: 2 is greater than the capacity 1. This is not a flow with a strange property, it is not a flow at all, and every conclusion drawn from it is meaningless.
\[ f(s,a) = 2 \ \not\le\ c(s,a) = 1 \]
An edge's capacity is a hard ceiling, not a suggestion. If more needs to move from s to a than one edge allows, it has to go by some other route entirely, using a different edge.
\[ c(s,a) = 1 \]
Respect the ceiling: f(s,a) at most 1
Why: Any valid assignment keeps this edge at 0 or 1. If the network needs to move more total flow from s, it must also use the separate edge from s to b, which has its own, independent capacity.
\[ f(s,a) \le 1, \quad \text{extra flow must use a different edge, e.g. } f(s,b) \le 1 \]
Notation
Annotate
From Trap: sending more than the pipe can carry — read this one piece at a time. What is each part doing?
On: \( f(s,a) = 2 \ \not\le\ c(s,a) = 1 \)
Concept
A flow's value is the total amount actually making it from source to sink, the number that matters. Because of conservation, you can measure it in either of two equal ways.
value of a flow — The net amount of flow leaving the source, written |f|. It equals the net amount arriving at the sink, because nothing is created or lost along the way.
\[ |f| \;=\; \sum_{v} f(s,v) \;=\; \sum_{v} f(v,t) \]
This equality is not a coincidence to verify by luck, it follows directly from conservation holding at every node strictly between s and t.
Matching
Match the pairs
Match each term to the definition this lesson gave it — not the one you would guess from the word.
Why: These are the working definitions of source, sink, capacity, flow conservation, value of a flow as Network Flow: Max-Flow Min-Cut uses them. Pairing them correctly is the test of whether you could state each one with the slide switched off.
Picture it
Animation
Shows: Conservation at every interior node — a rendered Manim animation.
Rendered with Manim.
Takeaway: The constraint that makes flow a flow rather than an arbitrary labelling.
Step zero
Discussion prompt
Compute the value of a flow — before any calculation: what is the plan? Name the moves in order, in plain English, without doing the arithmetic.
Hint: It starts with: Sum the flow leaving the source
Answer:
Worked example
Use the same valid flow as before: 1 on s to a, 1 on s to b, 0 on a to b, 1 on a to t, 1 on b to t. Find the value two ways.
Sum the flow leaving the source
Why: Only two edges leave s: s to a and s to b, carrying 1 unit each.
\[ \sum_v f(s,v) = f(s,a) + f(s,b) = 1 + 1 = 2 \]
Sum the flow arriving at the sink
Why: Only two edges enter t: a to t and b to t, carrying 1 unit each.
\[ \sum_v f(v,t) = f(a,t) + f(b,t) = 1 + 1 = 2 \]
Verify both totals agree
Why: Both computations give 2, exactly as conservation guarantees. The value of this flow is 2, whichever side you measure from.
\[ |f| = 2 \]
Picture it
Animation
Shows: Each line of the worked example "Compute the value of a flow", appearing one at a time.
The same working the example does, in the order a tutor would write it.
Takeaway: Both computations give 2, exactly as conservation guarantees. The value of this flow is 2, whichever side you measure from.
Section
Section 2
Concept
Given a current flow, the residual capacity of an edge is how much additional flow could still be pushed along it right now.
residual capacity — For an edge (u,v) carrying flow f(u,v) out of a total capacity c(u,v), the residual capacity is what remains unused: capacity minus current flow.
\[ c_f(u,v) \;=\; c(u,v) - f(u,v) \]
If an edge is carrying 1 out of a capacity of 1, its residual capacity is 0: completely full, nothing more can be pushed along it in the forward direction.
Intuition
Imagine you send flow along a path that looked promising, but it turns out to block off a better overall arrangement. Without some way to reroute, the algorithm would be stuck with its first choice forever.
The fix is to let the algorithm partially cancel an earlier decision, as if flowing backward along an edge that already carries flow. That is exactly what a back edge in the residual graph represents: an offer to undo, not a real physical pipe running the other way.
Concept
The residual graph for a given flow has, for every original edge, up to two residual edges: a forward one and a backward one.
residual graph — A graph built from the current flow: a forward residual edge (u,v) whenever capacity remains, and a backward residual edge (v,u) whenever there is flow on (u,v) to undo.
\[ c_f(u,v) = c(u,v) - f(u,v) \qquad \text{(forward, leftover capacity)} \]
\[ c_f(v,u) = f(u,v) \qquad \text{(backward, the flow available to undo)} \]
Traversing a forward residual edge sends new flow along a real edge. Traversing a backward residual edge cancels flow that was previously sent the other way. Both are legal moves in the residual graph.
Step zero
Discussion prompt
Compute every residual capacity in the network — before any calculation: what is the plan? Name the moves in order, in plain English, without doing the arithmetic.
Hint: It starts with: Compute the forward residuals
Answer:
Worked example
Take the flow from Section 1: 1 on s to a, 1 on s to b, 0 on a to b, 1 on a to t, 1 on b to t. Find the residual capacity of every possible edge, forward and backward.
Compute the forward residuals
Why: Forward residual capacity is capacity minus flow, for each of the five original edges.
| edge | capacity | flow | forward residual |
|---|---|---|---|
| s to a | 1 | 1 | 0 |
| s to b | 1 | 1 | 0 |
| a to b | 1 | 0 | 1 |
| a to t | 1 | 1 | 0 |
| b to t | 1 | 1 | 0 |
Compute the backward residuals
Why: Backward residual capacity equals the flow currently on that edge, since that is exactly how much could be undone.
| back edge | equals flow on | backward residual |
|---|---|---|
| a to s | s to a | 1 |
| b to s | s to b | 1 |
| b to a | a to b | 0 |
| t to a | a to t | 1 |
| t to b | b to t | 1 |
Verify: every residual capacity is non-negative and accounted for
Why: Every forward residual is capacity minus flow (never negative, since flow never exceeds capacity), and every backward residual equals a flow value (also never negative). All ten numbers above are consistent with the flow they came from.
Worked example
Start from zero flow. Suppose an algorithm greedily sends flow along the first path it notices, s to a to b to t, without any particular strategy.
Figure (svg): The s, a, b, t network with the path s to a, a to b, b to t highlighted in green each carrying flow 1 of capacity 1, while s to b and a to t remain at flow 0 of capacity 1.
Find the bottleneck of the chosen path
Why: The path s to a to b to t crosses three edges with capacities 1, 1, and 1. The bottleneck is the smallest residual capacity along the path, here 1.
\[ \text{bottleneck} = \min(c_f(s,a), c_f(a,b), c_f(b,t)) = \min(1,1,1) = 1 \]
Send 1 unit along the path
Why: Every edge on the path gets its flow increased by the bottleneck amount, 1. This saturates all three edges at once, since they all had capacity exactly 1.
\[ f(s,a)=1,\ f(a,b)=1,\ f(b,t)=1,\ f(s,b)=0,\ f(a,t)=0 \]
Build the resulting residual graph
Why: The three saturated edges now have forward residual 0, but each gains a backward residual edge equal to its flow. The two untouched edges keep their full forward residual capacity.
Figure (svg): Residual graph after the greedy step: forward edges s to b and a to t remain with residual capacity 1, while three dashed amber back edges appear, a to s, b to a, and t to b, each with residual capacity 1.
Verify the residual graph matches the table computed earlier
Why: Forward residuals of 0 on s to a, a to b, b to t, and 1 on s to b, a to t; backward residuals of 1 on a to s, b to a, t to b. This matches the ten values computed edge by edge in the previous slide, so the residual graph is built correctly.
Reverse engineer
Discussion prompt
Work backwards. The example finished here:
Verify the residual graph matches the table computed earlier
What was it asked to do, and what must it have been given? Reconstruct the problem from its answer.
Hint: Every quantity in the result had to enter somewhere. Account for each one.
Answer:
Start from zero flow. Suppose an algorithm greedily sends flow along the first path it notices, s to a to b to t, without any particular strategy.
Concept
An augmenting path is any path from source to sink in the current residual graph, where every edge on it has positive residual capacity. Forward and backward residual edges are both fair game.
augmenting path — A path from s to t through the residual graph along which every edge has residual capacity greater than 0. Sending flow along it strictly increases the value of the flow.
This is the whole point of the residual graph: it lets the search for more flow travel along a real leftover pipe, or backward to partially cancel a pipe that is already carrying flow, whichever leads somewhere useful.
Intuition
Watch me not know the answer. This is what the first two minutes actually look like.
Push flow greedily along whatever source-to-sink path you find, and never revisit a decision.
Try it: find any path with spare capacity and saturate it
Why: It is the obvious algorithm, it always terminates, and on most small networks it gives the right answer.
One bad first choice locks in a suboptimal answer
Why: Route flow through a middle edge that two different paths needed, and the second path is now blocked. No forward path remains, yet the flow is not maximum — and no amount of further forward searching will fix it.
Dead end. Not a mistake — a move that was worth trying and did not pay off. This happens in most proofs.
Back up. Allow a step to cancel an earlier one
Why: Give every used edge a residual back edge equal to the flow on it. Sending flow along that back edge means retract this much of the earlier decision, and now the search can repair its own mistakes.
The residual graph is not bookkeeping. It is the undo button that makes greedy correct. This is a general pattern: greedy plus a principled way to revoke a choice is often exactly enough.
The expert does not see the whole path in advance. The expert tries something, reads the result, and adjusts. That is the skill.
Ranking
Put in order
Put the moves of Find an augmenting path that uses a back edge into the order they have to happen.
Why: These are the moves of the worked example in the order it makes them, and each one is set up by the one before it. The edge s to b was never used by the greedy step, so its forward residual capacity is still 1.
Worked example
Continue from the residual graph just built, after the greedy step sent 1 unit along s to a to b to t. Search for another augmenting path from s to t.
Try s to b, using the untouched forward edge
Why: The edge s to b was never used by the greedy step, so its forward residual capacity is still 1. This is a legal first hop.
\[ c_f(s,b) = 1 \]
From b, cross the back edge to a
Why: The edge a to b currently carries 1 unit of flow, so the backward residual edge b to a has residual capacity equal to that flow, 1. Traversing it will cancel 1 unit of flow on a to b.
\[ c_f(b,a) = f(a,b) = 1 \]
From a, take the untouched forward edge to t
Why: The edge a to t was never used, so its forward residual capacity is still 1. The path s to b to a to t is complete, with bottleneck 1.
\[ \text{bottleneck} = \min(1,1,1) = 1 \]
Augment along this path
Why: Increase flow by 1 on the two forward edges used, s to b and a to t. Decrease flow by 1 on the edge whose back edge was used, a to b, since crossing a back edge cancels flow on the original edge.
\[ f(s,b): 0 \to 1, \qquad f(a,t): 0 \to 1, \qquad f(a,b): 1 \to 0 \]
Verify the new flow is valid and larger
Why: The resulting flow is f(s,a)=1, f(s,b)=1, f(a,b)=0, f(a,t)=1, f(b,t)=1: exactly the valid flow verified in Section 1, with value 2. Conservation still holds at a (in 1, out 1) and at b (in 1, out 1), and the value grew from 1 to 2. The back edge did not add a new physical pipe, it rerouted flow that the greedy step had trapped.
Picture it
Animation
Shows: Find a path with spare capacity, then push — a rendered Manim animation.
Rendered with Manim.
Takeaway: The bottleneck edge is what limits the whole path.
Anomaly
Predict first
A student writes this, and it looks reasonable:
After the greedy step sends 1 unit along s to a to b to t, a student builds a residual graph using only forward edges, the leftover capacity, and ignores the possibility of undoing flow.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: Without back edges, s to b leads to b, and there is no forward edge from b to a or b to t left, so the search dead-ends.
The residual graph always includes backward edges, one for every edge currently carrying flow, with residual capacity equal to that flow.
Why: Without back edges, s to b leads to b, and there is no forward edge from b to a or b to t left, so the search dead-ends. The student reports the maximum flow as 1, the value found after the very first path.
Trap
After the greedy step sends 1 unit along s to a to b to t, a student builds a residual graph using only forward edges, the leftover capacity, and ignores the possibility of undoing flow.
In that forward-only picture, the only edges with residual capacity are s to b and a to t, and they do not connect to each other (no edge from b to a exists going forward).
Conclude no augmenting path exists and stop
Why: Without back edges, s to b leads to b, and there is no forward edge from b to a or b to t left, so the search dead-ends. The student reports the maximum flow as 1, the value found after the very first path.
\[ \text{reported (wrong) max flow} = 1 \]
The residual graph always includes backward edges, one for every edge currently carrying flow, with residual capacity equal to that flow.
Adding the back edge b to a (residual capacity 1, since a to b carries 1 unit of flow) reopens the search: s to b to a to t is a full augmenting path.
Augment along s to b to a to t and find the true maximum
Why: This path was only visible because the back edge b to a exists. Augmenting along it raises the value from 1 to 2, and no augmenting path remains afterward, since s to a and s to b become saturated with nothing left to reach t.
\[ \text{true max flow} = 2 \]
Section
Section 3
Concept
The Ford-Fulkerson method finds a maximum flow with one repeated move: find any augmenting path in the residual graph, push as much flow as the bottleneck allows, rebuild the residual graph, and repeat.
Ford-Fulkerson method — Start with zero flow. While an augmenting path from s to t exists in the residual graph, augment along it. Stop when no augmenting path remains.
It is called a method rather than a single algorithm because it does not say which augmenting path to pick when several are available, only that you must keep going until none exist.
Concept
Find any path from source to sink with room left on it, push as much as its tightest edge allows, and repeat until no such path exists.
FORD-FULKERSON(G, s, t)
for each edge (u, v)
f(u, v) = 0
while an augmenting path P exists in G_f
b = min residual capacity along P
for each edge (u, v) in P
f(u, v) = f(u, v) + b
f(v, u) = f(v, u) - b
return fLine 8 is the one that looks wrong and is not. Sending flow forward creates the option of sending it back later, and that back edge is what lets a later path undo an earlier bad routing decision. Without it the method would get stuck at a non-maximum flow.
Notation
Every line of FORD-FULKERSON says one thing. Read the line, then read what it does — not the other way round.
Annotate
Invariant
The flow is legal at every step: no edge exceeds its capacity, and everything into a middle vertex comes back out. Only the total ever rises.
Step through it
At each path, find the bottleneck edge yourself before stepping.
Picture it
Animation
Shows: FORD-FULKERSON executing: the current line of pseudocode is highlighted while the data it touches changes.
Rendered with Manim.
Takeaway: Push the bottleneck amount along any path with room left; the back edges are what let a later path undo an earlier choice.
Intuition
Each augmenting path is one more trip that carries some water from source to sink. As long as some route, forward or backward through the residual graph, can still carry something, there is more flow to find.
The method only declares victory when every route from s to t in the residual graph is completely blocked, not before. Stopping early just because the most recent path looked big is exactly the mistake to avoid.
Picture it
Figure (svg): A network with s to a capacity 10, a to t capacity 10, s to b capacity 1, and b to t capacity 1. There is no edge between a and b.
Discussion prompt
Read the picture before the words. What is this showing, and what is the one thing it is built to make obvious? Commit to an answer, then read on.
Hint: Name the parts, then say what changes between them — and if nothing changes, say what is being held still.
Answer:
Consider a different network: s to a with capacity 10, a to t with capacity 10, s to b with capacity 1, and b to t with capacity 1. There is no edge between a and b.
Worked example
Consider a different network: s to a with capacity 10, a to t with capacity 10, s to b with capacity 1, and b to t with capacity 1. There is no edge between a and b.
Figure (svg): A network with s to a capacity 10, a to t capacity 10, s to b capacity 1, and b to t capacity 1. There is no edge between a and b.
Find an augmenting path and its bottleneck
Why: Starting from zero flow, the path s to a to t is available, with residual capacities 10 and 10 on its two edges. The bottleneck is the smaller of the two, but here they are equal.
\[ \text{bottleneck} = \min(c_f(s,a), c_f(a,t)) = \min(10,10) = 10 \]
Augment by 10 along s to a to t
Why: Both edges on this path get their flow raised by 10, saturating them completely.
\[ f(s,a) = 10, \quad f(a,t) = 10, \quad \text{value so far} = 10 \]
Check whether this is already the final answer
Why: The path used was the biggest-looking one in the network, but the method's stopping rule only cares whether an augmenting path still exists, not how large the last one felt. That check comes next, on the residual graph.
Blank canvas
Draw it
Draw what Ford-Fulkerson, iteration 1: send the big path just did — the shape of it, not the line-by-line working. One picture, labels only where you need them. Then check it against the steps: anything you could not draw is a step you followed rather than understood.
Step zero
Discussion prompt
Ford-Fulkerson, iteration 2: find what's left — before any calculation: what is the plan? Name the moves in order, in plain English, without doing the arithmetic.
Hint: It starts with: Check the residual graph for another augmenting path
Answer:
Worked example
After sending 10 units along s to a to t, both of those edges are saturated: their forward residual capacity is 0. But the method is not finished, since s to t routes might still exist elsewhere.
Check the residual graph for another augmenting path
Why: The edges s to b and b to t were never touched, so their forward residual capacity is still their full capacity, 1 each. The path s to b to t is available.
\[ c_f(s,b) = 1, \quad c_f(b,t) = 1 \]
Augment by 1 along s to b to t
Why: The bottleneck of this path is 1, so both edges are raised by 1, saturating them too.
\[ f(s,b) = 1, \quad f(b,t) = 1, \quad \text{new total value} = 10 + 1 = 11 \]
Confirm no augmenting path remains
Why: Every edge leaving s, both s to a and s to b, is now saturated with forward residual 0. Since s has no other way out in the residual graph, no augmenting path from s to t can exist. The method halts.
Verify the final value against the network's own limit
Why: The total capacity leaving s is 10 plus 1, which is 11. The flow found, 11, exactly matches that ceiling, so no larger flow was possible in the first place.
\[ \text{max flow} = 11 = c(s,a) + c(s,b) \]
Picture it
Animation
Shows: Each line of the worked example "Ford-Fulkerson, iteration 2: find what's left", appearing one at a time.
The same working the example does, in the order a tutor would write it.
Takeaway: The edges s to b and b to t were never touched, so their forward residual capacity is still their full capacity, 1 each. The path s to b to t is available.
Intuition
What feels wrong about this?
You push flow along the fattest path you can find, then look again and no forward path from source to sink survives.
\[ \text{no forward path} \;\Rightarrow\; \text{done?} \]
_Plain English only. No notation, no algebra. Just say what bothers you._
The feeling: you committed to a route early and now you are stuck with it, even though a different early choice might have left more room.
That feeling is the proof. It is not a substitute for the proof — it is the thing the proof writes down.
That is exactly what residual back edges fix. They let a later step undo part of an earlier commitment, which is why greedy without an undo button is not enough here — and why the stopping condition is about the residual graph, not the original one.
Anomaly
Predict first
A student writes this, and it looks reasonable:
A student sends 10 units along s to a to t, the obviously largest-looking path in the network, and stops there, assuming the biggest pipe must be the whole story.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: This misses the entirely separate route through b.
Picking a big path first is a fine start, but the method's stopping condition is about the residual graph, not about how impressive the last path felt.
Why: This misses the entirely separate route through b. The edge s to b (capacity 1) and b to t (capacity 1) were never touched, so 1 more unit of flow is sitting right there, unused. Ford-Fulkerson is not finished until no augmenting path remains, no matter how large the first one looked.
Trap
A student sends 10 units along s to a to t, the obviously largest-looking path in the network, and stops there, assuming the biggest pipe must be the whole story.
\[ \text{reported (wrong) max flow} = 10 \]
Declare victory after one big path
Why: This misses the entirely separate route through b. The edge s to b (capacity 1) and b to t (capacity 1) were never touched, so 1 more unit of flow is sitting right there, unused. Ford-Fulkerson is not finished until no augmenting path remains, no matter how large the first one looked.
Picking a big path first is a fine start, but the method's stopping condition is about the residual graph, not about how impressive the last path felt.
\[ \text{stop only when no augmenting path remains} \]
Keep searching after every augmentation
Why: After the 10-unit path, check the residual graph again: s to b to t is still open, with bottleneck 1. Augmenting there brings the true total to 11. Only now, with both edges out of s saturated, is the method actually done.
\[ \text{true max flow} = 11 \]
Translation
\( \text{stop only when no augmenting path remains} \)
Draw it
Translate both ways. First write the expression above as a sentence with no symbols in it at all. Then cover it, and write your sentence back as notation. If the two versions disagree, the disagreement is the thing to fix.
Concept
For integer capacities, every augmenting path has a bottleneck of at least 1, since residual capacities are whole numbers whenever capacities and flow start as whole numbers.
\[ \text{each augmentation raises } |f| \text{ by at least } 1 \]
Since the flow's value can never exceed the total capacity leaving the source, a finite ceiling, the method cannot augment forever. It must halt after finitely many steps, having found some maximum flow.
Concept
The Ford-Fulkerson method leaves open which augmenting path to choose. Edmonds-Karp fixes a specific rule: always pick a shortest augmenting path, the one with the fewest edges, found by a breadth-first search of the residual graph.
Edmonds-Karp — The Ford-Fulkerson method where every augmenting path is chosen to be a shortest path, in number of edges, using breadth-first search on the residual graph.
It still uses the exact same residual graph machinery, forward and backward edges included. The only change is the search strategy used to pick which augmenting path to take next.
Intuition
An arbitrary choice of augmenting path can, on some networks, force an enormous number of tiny augmentations before finishing, one painstaking unit at a time.
Always taking a shortest path prevents that slow crawl: it can be proven that the shortest-path distance from s to t never decreases as augmentations happen, which bounds the total number of iterations by a polynomial in the size of the network.
Step zero
Discussion prompt
An Edmonds-Karp trace — before any calculation: what is the plan? Name the moves in order, in plain English, without doing the arithmetic.
Hint: It starts with: Find the shortest augmenting paths available
Answer:
Worked example
Return to the s, a, b, t network with all five capacities equal to 1. Run Edmonds-Karp from zero flow, always taking a shortest augmenting path.
Find the shortest augmenting paths available
Why: From s to t, the paths s to a to t and s to b to t both have length 2 edges, while s to a to b to t has length 3. A breadth-first search finds a length-2 path first.
\[ \text{length}(s{\to}a{\to}t) = 2, \quad \text{length}(s{\to}b{\to}t) = 2, \quad \text{length}(s{\to}a{\to}b{\to}t) = 3 \]
Augment along s to a to t
Why: Bottleneck is 1. This saturates s to a and a to t.
\[ f(s,a) = 1, \quad f(a,t) = 1, \quad \text{value} = 1 \]
Search again and augment along s to b to t
Why: The remaining shortest augmenting path is s to b to t, length 2, bottleneck 1. This saturates s to b and b to t.
\[ f(s,b) = 1, \quad f(b,t) = 1, \quad \text{value} = 2 \]
Verify no augmenting path remains
Why: Both edges leaving s, s to a and s to b, are now saturated with forward residual 0, so nothing can leave s in the residual graph. The algorithm halts with value 2, matching the true maximum found earlier. Choosing shortest paths reached the same answer as the back-edge route, without needing to traverse a back edge at all on this particular network.
Picture it
Animation
Shows: Each line of the worked example "An Edmonds-Karp trace", appearing one at a time.
The same working the example does, in the order a tutor would write it.
Takeaway: Both edges leaving s, s to a and s to b, are now saturated with forward residual 0, so nothing can leave s in the residual graph. The algorithm halts with value 2, matching the true maximum found earlier. Choosing shortest paths reached the same answer as the back-edge route, without needing to traverse a back edge at all on this particular network.
Concept
Because always taking a shortest path bounds how many augmentations can happen, Edmonds-Karp runs in time polynomial in the size of the network, regardless of how large the edge capacities are.
\[ O(V \cdot E^{2}) \]
V is the number of nodes and E is the number of edges. The exact bound is a fact to remember, not something to re-derive here, but the key point is that it does not depend on the capacities at all, unlike an arbitrary choice of augmenting paths.
Pattern
1. Start with the zero flow
Why: Every edge begins carrying nothing. This is always a valid flow, since 0 is within every capacity and conservation trivially holds.
2. Build the residual graph from the current flow
Why: Forward edges get leftover capacity, capacity minus flow. Backward edges get residual capacity equal to the current flow, wherever flow exists.
3. Find an augmenting path from s to t (shortest, for Edmonds-Karp)
Why: Any path where every edge, forward or backward, has positive residual capacity. Edmonds-Karp specifically uses breadth-first search to find a shortest one.
4. Augment by the bottleneck, then repeat
Why: Raise flow on forward edges and lower flow on edges whose back edge was used, by the path's minimum residual capacity. Rebuild the residual graph and search again. Stop only when no augmenting path exists.
Elimination
Eliminate the wrong options
Which of these is a valid augmenting path in the residual graph at this point?
3 of these 4 are wrong. Strike them one at a time, and say what rules each one out before you strike the next. The survivor is the answer.
Survives elimination: A
Why: Check every edge: s to b has forward residual 1 (untouched), the back edge b to a has residual capacity equal to the flow on a to b, which is 1, and a to t has forward residual 1 (untouched). All three are positive, so the full path is augmenting.
Check
Right after the greedy step sends 1 unit along s to a to b to t (so f(s,a)=1, f(a,b)=1, f(b,t)=1, and f(s,b)=f(a,t)=0), consider four candidate paths from s to t.
Check your understanding
Which of these is a valid augmenting path in the residual graph at this point?
Answer: A
Why: Check every edge: s to b has forward residual 1 (untouched), the back edge b to a has residual capacity equal to the flow on a to b, which is 1, and a to t has forward residual 1 (untouched). All three are positive, so the full path is augmenting.
Section
Section 4
Concept
An s-t cut splits every node in the network into two groups: one group containing the source, the other containing the sink.
s-t cut — A split of all nodes into two sets S and T, where the source is in S and the sink is in T. Written as the pair (S,T).
Any such split is a valid cut, no matter how the internal nodes are distributed between the two sides, as long as s ends up in S and t ends up in T.
Concept
A cut's capacity only counts edges crossing from the S side to the T side, in that direction. Edges running from T back to S, or edges with both ends on the same side, are not counted at all.
cut capacity — The sum of capacities of every edge that starts in S and ends in T. Edges from T to S do not count toward it, even if they exist.
\[ c(S,T) \;=\; \sum_{u \in S,\ v \in T} c(u,v) \]
Intuition
Every unit of flow leaving s and reaching t must, at some point, cross from the S side to the T side of any cut you pick. So a cut's capacity is an upper limit on how much flow could possibly get through, no matter how cleverly it is routed.
Some cuts are generous, with a huge combined capacity. Others are tight bottlenecks. The tightest one of all turns out to say something exact about the maximum flow, not just an approximate bound.
Picture it
Figure (svg): The s, a, b, t network with a dashed boundary separating s alone on the S side from a, b, t on the T side. The two crossing edges, s to a and s to b, are highlighted in red as the cut edges.
Discussion prompt
Read the picture before the words. What is this showing, and what is the one thing it is built to make obvious? Commit to an answer, then read on.
Hint: Name the parts, then say what changes between them — and if nothing changes, say what is being held still.
Answer:
On the s, a, b, t network, consider the cut with S containing only s, and T containing a, b, and t.
Worked example
On the s, a, b, t network, consider the cut with S containing only s, and T containing a, b, and t.
Figure (svg): The s, a, b, t network with a dashed boundary separating s alone on the S side from a, b, t on the T side. The two crossing edges, s to a and s to b, are highlighted in red as the cut edges.
List every edge from S to T
Why: S contains only s. The edges leaving s are s to a and s to b, and both end in T. No other edge starts in S, since S has only one node.
| edge | from side | to side | counts toward cut |
|---|---|---|---|
| s to a | S | T | yes |
| s to b | S | T | yes |
| a to b | T | T | no |
| a to t | T | T | no |
| b to t | T | T | no |
Add up their capacities
Why: Only s to a and s to b cross from S to T. The edges a to b, a to t, and b to t all sit entirely inside T, so none of them count.
\[ c(S,T) = c(s,a) + c(s,b) = 1 + 1 = 2 \]
Verify by counting what could not possibly be excluded
Why: Every edge leaving S was included exactly once, and no edge inside T or entering S was counted. The capacity of this cut is 2.
Invariant
Step through it
Step through Compute a cut's capacity one row at a time. One of these columns never changes — find it, and say why it cannot.
Intuition
What move should we make next?
You have a flow of value 23. You have searched and found no augmenting path.
\[ |f| = 23, \qquad \text{is 24 possible?} \]
Not finding a path is evidence about your search, not about the network.
You need something that rules out 24 for every possible flow, not just yours. What kind of object would do that, and have you seen this pattern before?
_Look at your toolkit. Say a move number out loud before this slide advances._ A wrong guess is useful. A silent guess is not.
Concept
Here is the easier half of the big theorem: no matter which flow you have and which cut you pick, the flow's value can never exceed that cut's capacity.
\[ |f| \;\le\; c(S,T) \qquad \text{for every flow } f \text{ and every cut } (S,T) \]
The reasoning is simple: every unit of flow leaving s must eventually cross from S to T to reach t, and the edges crossing that way cannot carry more than their combined capacity, the cut's capacity.
Concept
Every proof of this kind has the same five or six moves in the same order. The order is not something you rediscover each time.
It is on the right. It will stay on the right through the worked examples that follow.
Why this matters: the structure is now handled. You are not spending working memory on what comes next — you are spending all of it on the one hard step.
Step 2 is usually easy and step 4 is one line. Step 3 is the whole theorem — you must actually construct the matching object, not merely argue one exists.
Concept
The move: #16 (Certificate of optimality).
Prove a ceiling that applies to every solution
Why: Every flow crossing any s-t cut is bounded by that cut's capacity. So every cut is a ceiling on every flow, forever, regardless of what algorithm produced it.
\[ |f| \le c(S, T) \quad \text{for every flow } f \text{ and every cut } (S, T) \]
Then exhibit one instance of the ceiling that equals your value
Why: Find a specific cut whose capacity is exactly 23. Now no flow can exceed 23, and yours achieves it — so yours is maximum and that cut is minimum, both settled at once.
Say where the certificate comes from
Why: Take the vertices reachable from the source in the final residual graph. That set is the cut, and it is read straight off the algorithm's final state — not searched for separately.
This is what proof gives you that testing cannot. No amount of running the algorithm establishes that 24 is impossible; one cut of capacity 23 establishes it permanently.
Ranking
Put in order
Put the moves of Verify weak duality against three cuts into the order they have to happen.
Why: These are the moves of the worked example in the order it makes them, and each one is set up by the one before it. Only s to a and s to b cross, both capacity 1, giving cut capacity 2.
Worked example
The maximum flow found earlier on the s, a, b, t network has value 2. Check that this value is at most the capacity of several different cuts.
Cut 1: S is s alone
Why: Only s to a and s to b cross, both capacity 1, giving cut capacity 2.
\[ c(S,T) = 1 + 1 = 2 \quad \ge\quad |f| = 2 \]
Cut 2: S is s and a together
Why: Now the crossing edges are s to b (s is in S, b is in T) and a to t (a is in S, t is in T), plus a to b (a in S, b in T). That is three crossing edges, capacity 1 each.
\[ c(S,T) = c(s,b) + c(a,b) + c(a,t) = 1+1+1 = 3 \quad \ge\quad |f| = 2 \]
Cut 3: S is s, a, and b together
Why: Now only a to t and b to t cross into T, which contains just t. Capacity 1 each.
\[ c(S,T) = c(a,t) + c(b,t) = 1+1 = 2 \quad \ge\quad |f| = 2 \]
Verify: the flow's value never exceeded any cut's capacity
Why: 2 is at most 2, at most 3, and at most 2 again. Weak duality held in every case, and two of these three cuts, capacity 2, are exactly tied with the flow's value. That tie is not a coincidence, it is what the full theorem is about.
Picture it
Animation
Shows: Each line of the worked example "Verify weak duality against three cuts", appearing one at a time.
The same working the example does, in the order a tutor would write it.
Takeaway: 2 is at most 2, at most 3, and at most 2 again. Weak duality held in every case, and two of these three cuts, capacity 2, are exactly tied with the flow's value. That tie is not a coincidence, it is what the full theorem is about.
Intuition
What move should we make next?
The theorem says these three are the same statement:
Which of the three implications is nearly free, and which one requires you to build something? Name the move for the hard one.
_Look at your toolkit. Say a move number out loud before this slide advances._ A wrong guess is useful. A silent guess is not.
Concept
Weak duality says the maximum possible flow can never beat the smallest cut's capacity. The max-flow min-cut theorem says something much stronger: they are always exactly equal.
max-flow min-cut theorem — In any flow network, the value of a maximum flow equals the capacity of a minimum s-t cut. Neither one can ever be smaller than the other.
\[ \max_{f} |f| \;=\; \min_{(S,T)} c(S,T) \]
This is what makes flow algorithms trustworthy: whenever an algorithm halts with no augmenting path left, it has automatically also produced a cut with matching capacity, which is proof, on the spot, that no larger flow could ever exist.
Picture it
Animation
Shows: Max-flow equals min-cut — a rendered Manim animation.
Rendered with Manim.
Takeaway: Two very different-looking quantities, provably identical.
Picture it
Figure (svg): The final residual graph: s has no outgoing residual edges at all, since s to a and s to b are both saturated, while a to b remains open with residual 1 and four dashed amber back edges point into s, a, and b from the saturated edges.
Discussion prompt
Read the picture before the words. What is this showing, and what is the one thing it is built to make obvious? Commit to an answer, then read on.
Hint: Name the parts, then say what changes between them — and if nothing changes, say what is being held still.
Answer:
Take the final residual graph of the s, a, b, t network at its maximum flow of value 2, where f(s,a)=1, f(s,b)=1, f(a,b)=0, f(a,t)=1, f(b,t)=1.
Worked example
Take the final residual graph of the s, a, b, t network at its maximum flow of value 2, where f(s,a)=1, f(s,b)=1, f(a,b)=0, f(a,t)=1, f(b,t)=1.
Figure (svg): The final residual graph: s has no outgoing residual edges at all, since s to a and s to b are both saturated, while a to b remains open with residual 1 and four dashed amber back edges point into s, a, and b from the saturated edges.
Find every node reachable from s in this residual graph
Why: Both edges leaving s in the original graph, s to a and s to b, are saturated, so their forward residual is 0. No other edge starts at s. Therefore s can reach nothing at all, and the reachable set is just s itself.
\[ S = \{s\}, \qquad T = \{a,b,t\} \]
Read off the cut this defines
Why: This S and T form a genuine s-t cut, and its capacity is the sum of the original capacities of edges leaving S: s to a plus s to b.
\[ c(S,T) = c(s,a) + c(s,b) = 1 + 1 = 2 \]
Verify the max flow equals this cut's capacity
Why: The maximum flow found by hand earlier has value 2, and this cut also has capacity 2. They match exactly, confirming the theorem on this network: this cut is a minimum cut, and 2 is truly the maximum flow, not just a flow someone happened to stop at.
\[ |f^{*}| = 2 = c(S,T) \]
Reverse engineer
Discussion prompt
Work backwards. The example finished here:
Verify the max flow equals this cut's capacity
What was it asked to do, and what must it have been given? Reconstruct the problem from its answer.
Hint: Every quantity in the result had to enter somewhere. Account for each one.
Answer:
Take the final residual graph of the s, a, b, t network at its maximum flow of value 2, where f(s,a)=1, f(s,b)=1, f(a,b)=0, f(a,t)=1, f(b,t)=1.
Anomaly
Predict first
A student writes this, and it looks reasonable:
A student computes the maximum flow one way, gets a value, then separately estimates a cut's capacity a different, sloppier way, gets a different number, and concludes the two ideas are merely related but not actually equal.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: This treats the theorem as a rough rule of thumb rather than an exact equality.
The theorem is an exact equality, always. If a computed flow value and a computed cut capacity disagree, one of the two computations has a mistake in it, not the theorem.
Why: This treats the theorem as a rough rule of thumb rather than an exact equality. In fact the mismatch is a signal that the cut was computed wrong, most likely by counting an edge that runs from T back to S, or an edge that sits entirely inside one side, which never counts toward a cut's capacity.
Trap
A student computes the maximum flow one way, gets a value, then separately estimates a cut's capacity a different, sloppier way, gets a different number, and concludes the two ideas are merely related but not actually equal.
\[ \text{their flow: } 2 \qquad \text{their "cut": } 3 \ (\text{miscounted}) \]
Accept the mismatch as normal
Why: This treats the theorem as a rough rule of thumb rather than an exact equality. In fact the mismatch is a signal that the cut was computed wrong, most likely by counting an edge that runs from T back to S, or an edge that sits entirely inside one side, which never counts toward a cut's capacity.
The theorem is an exact equality, always. If a computed flow value and a computed cut capacity disagree, one of the two computations has a mistake in it, not the theorem.
\[ \max_{f}|f| \;=\; \min_{(S,T)} c(S,T) \quad \text{(always, no exceptions)} \]
Recompute the cut, counting only S-to-T edges
Why: For S equal to s alone, only s to a and s to b cross, giving capacity 2, not 3. Once counted correctly, the cut's capacity is exactly 2, matching the flow's value exactly. There is no gap to explain away.
\[ c(S,T) = c(s,a) + c(s,b) = 2 = |f^{*}| \]
Break the constraint
Discussion prompt
The rule this trap just fixed:
The theorem is an exact equality, always. If a computed flow value and a computed cut capacity disagree, one of the two computations has a mistake in it, not the theorem.
Now break it on purpose. Build a case that violates it and follow the consequences until something visibly fails. Where does the failure first show up — and would you have noticed it if you had not been looking?
Hint: The dangerous rules are the ones whose violation still produces an answer. If yours fails loudly, try to find one that fails quietly.
Answer:
This treats the theorem as a rough rule of thumb rather than an exact equality. In fact the mismatch is a signal that the cut was computed wrong, most likely by counting an edge that runs from T back to S, or an edge that sits entirely inside one side, which never counts toward a cut's capacity.
Pattern
1. Run the flow algorithm to completion
Why: Keep augmenting until the residual graph has no path left from s to t. What remains is a maximum flow.
2. Find every node reachable from s in the final residual graph
Why: Search forward and backward residual edges alike, starting at s. Call this reachable set S, and everything else T.
3. Read the cut edges from the original graph, not the residual one
Why: The minimum cut's capacity is the sum of original capacities on edges that start in S and end in T, using the real network, not residual capacities.
4. Confirm the capacity equals the flow's value
Why: By the theorem, this always matches. If it does not, recheck which edges were counted as crossing from S to T.
Real world
Discussion prompt
Outside this lesson: where does Network Flow: Max-Flow Min-Cut actually turn up? Name one concrete situation — a job, a piece of software someone ships, a decision somebody has to make — and say which part of Reading a minimum cut off the residual graph is doing the work in it.
Hint: Vague is the failure mode here. "Engineering" is not a situation; "deciding whether this build is fast enough to ship" is.
Answer:
Flow networks, the two rules a valid flow obeys, residual graphs and why augmenting paths need back edges, Ford-Fulkerson and Edmonds-Karp, the max-flow min-cut theorem, and the bipartite-matching reduction. Targets four real misconceptions: exceeding an edge's capacity, forgetting residual back edges, confusing the max-flow value with the min-cut capacity, and assuming a single greedy highest-capacity path finishes the job.
Prediction
Predict first
According to the max-flow min-cut theorem, what must be true of every s-t cut in that network?
Answer it in your own words, now, with nothing to choose from. The options are on the next slide — and picking the right one off a list is an easier skill than producing it.
Correct: Every cut has capacity at least 7, and at least one cut has capacity exactly 7.
Why: Weak duality guarantees every cut's capacity is at least the maximum flow's value, so at least 7 for every cut. The theorem additionally guarantees the minimum cut achieves exact equality with the maximum flow, so some cut has capacity exactly 7.
Check
Suppose you are told that the maximum flow in some network has value 7.
Check your understanding
According to the max-flow min-cut theorem, what must be true of every s-t cut in that network?
Answer: A
Why: Weak duality guarantees every cut's capacity is at least the maximum flow's value, so at least 7 for every cut. The theorem additionally guarantees the minimum cut achieves exact equality with the maximum flow, so some cut has capacity exactly 7.
Section
Section 5
Concept
A bipartite graph has two separate groups of nodes, Left and Right, with edges only running between the groups, never within a group.
matching — A set of edges in a bipartite graph where no two chosen edges share an endpoint. Each Left node is paired with at most one Right node, and vice versa.
The goal is usually a maximum matching: the largest possible set of such non-overlapping pairs. This models job assignment, roommate pairing, and many scheduling problems.
Picture it
Animation
Shows: Matching, reduced to flow — a rendered Manim animation.
Rendered with Manim.
Takeaway: A different problem, solved by the machinery you already built.
Concept
A perfect matching pairs up every single node on both sides, with nobody left out. It only exists when the two sides are the same size and the edges cooperate.
perfect matching — A matching that covers every node on both the Left and Right sides. Every perfect matching is a maximum matching, but not every maximum matching is perfect.
A maximum matching always exists (it might just be empty in the worst case), but a perfect matching might not, if the available edges simply do not allow everyone to be paired.
Intuition
Picture every Left node sending a single unit of supply, and every Right node able to absorb only a single unit of demand. An edge between a Left and Right node is a route that one unit can travel along, but never more than one.
That single-unit restriction is exactly what an edge capacity of 1 enforces. Once the whole picture is a flow network, finding the biggest matching becomes finding the biggest flow.
Picture it
Animation
Shows: Integer capacities give integer flows — a rendered Manim animation.
Rendered with Manim.
Takeaway: Which is what lets flow solve matching problems.
Concept
Add one new source node connected to every Left node, and one new sink node that every Right node connects to. Give every added edge, and every original edge, capacity 1.
\[ c(s, \ell) = 1 \ \forall \ell \in \text{Left}, \qquad c(\ell, r) = 1 \ \text{for each original edge}, \qquad c(r, t) = 1 \ \forall r \in \text{Right} \]
A maximum flow in this new network has an integer value, since every capacity is a whole number, and that integer flow translates directly back into a matching: an edge between a Left and Right node is part of the matching exactly when it carries flow 1.
Picture it
Figure (svg): A bipartite flow network: a source connects to L1, L2, and L3, each with capacity 1. L1 connects to R1, L2 connects to both R1 and R2, and L3 connects to R2, each edge capacity 1. R1 and R2 each connect to a sink with capacity 1.
Discussion prompt
Read the picture before the words. What is this showing, and what is the one thing it is built to make obvious? Commit to an answer, then read on.
Hint: Name the parts, then say what changes between them — and if nothing changes, say what is being held still.
Answer:
Three workers, L1, L2, L3, and two tasks, R1, R2. L1 can only do R1. L2 can do either R1 or R2. L3 can only do R2. Model this as flow and find the maximum matching.
Worked example
Three workers, L1, L2, L3, and two tasks, R1, R2. L1 can only do R1. L2 can do either R1 or R2. L3 can only do R2. Model this as flow and find the maximum matching.
Figure (svg): A bipartite flow network: a source connects to L1, L2, and L3, each with capacity 1. L1 connects to R1, L2 connects to both R1 and R2, and L3 connects to R2, each edge capacity 1. R1 and R2 each connect to a sink with capacity 1.
Notice the bottleneck before computing anything
Why: Only two edges lead into the sink, R1 to t and R2 to t, each capacity 1. No matter how generous the Left side is, the sink can never absorb more than 2 units total.
\[ \text{max possible flow} \le c(R1,t) + c(R2,t) = 1 + 1 = 2 \]
Send flow along s to L1 to R1 to t
Why: Every edge on this path has capacity 1 and is untouched, so the bottleneck is 1. This matches L1 with R1.
\[ f(s,L1)=1,\ f(L1,R1)=1,\ f(R1,t)=1 \]
Send flow along s to L3 to R2 to t
Why: This path is also untouched, bottleneck 1. This matches L3 with R2.
\[ f(s,L3)=1,\ f(L3,R2)=1,\ f(R2,t)=1, \quad \text{total value} = 2 \]
Verify no augmenting path remains, and read off the matching
Why: Both edges into t are now saturated, so no more flow can reach the sink; the max flow is 2, matching the bottleneck spotted at the start. L2 carries no flow, since both R1 and R2 are already taken. The matching is L1 with R1 and L3 with R2, size 2, which is the maximum matching for this bipartite graph.
Notation
Annotate
From Solve a matching problem with max flow — read this one piece at a time. What is each part doing?
On: \( f(s,L3)=1,\ f(L3,R2)=1,\ f(R2,t)=1, \quad \text{total value} = 2 \)
Concept
Capacity 1 on every source-to-Left and Right-to-sink edge is not a simplification, it is what makes the translation back to a matching valid at all.
\[ f(s,\ell) \le 1 \ \Rightarrow\ \ell \text{ is used in at most one matched pair} \]
Because the maximum flow here is always an integer (every capacity is a whole number), each Left node either sends its single unit down exactly one Left-Right edge, or sends nothing. That is precisely what being matched to at most one partner means.
Picture it
Animation
Shows: Back edges let the algorithm change its mind — a rendered Manim animation.
Rendered with Manim.
Takeaway: Without them a greedy first choice could never be undone, and the answer would be wrong.
Anomaly
Predict first
A student writes this, and it looks reasonable:
A student builds the same source and sink but leaves the source-to-Left edges without a capacity limit, thinking capacity only matters for the original bipartite edges.
It is wrong. Say what breaks — and say it before you turn the page.
Correct: With no cap on s to L2, a max-flow algorithm is free to push 1 unit through each of L2's two edges simultaneously, for a total of 2 units leaving L2.
Every source-to-Left edge, and every Right-to-sink edge, must have capacity exactly 1, the same as the original bipartite edges.
Why: With no cap on s to L2, a max-flow algorithm is free to push 1 unit through each of L2's two edges simultaneously, for a total of 2 units leaving L2. That would mean L2 is matched to two tasks at the same time, which is not a matching at all.
Trap
A student builds the same source and sink but leaves the source-to-Left edges without a capacity limit, thinking capacity only matters for the original bipartite edges.
\[ c(s, L2) = \infty \ \text{(mistakenly uncapped)} \]
Let L2 send flow along both L2 to R1 and L2 to R2 at once
Why: With no cap on s to L2, a max-flow algorithm is free to push 1 unit through each of L2's two edges simultaneously, for a total of 2 units leaving L2. That would mean L2 is matched to two tasks at the same time, which is not a matching at all.
Every source-to-Left edge, and every Right-to-sink edge, must have capacity exactly 1, the same as the original bipartite edges.
\[ c(s, L2) = 1 \]
Cap L2's supply at 1 unit total
Why: With c(s, L2) = 1, conservation at L2 forces its total outgoing flow to also be at most 1, so at most one of L2 to R1 or L2 to R2 can carry flow. L2 ends up matched to at most one task, exactly as a valid matching requires.
Two truths and a lie
Sort into buckets
Some of these hold up and some are the exact mistakes this lesson is built to prevent. Sort them.
Check
In the bipartite matching flow network above, capacity 1 everywhere, suppose a completed maximum flow has value 2 while there are 3 Left nodes total.
Check your understanding
What can you correctly conclude?
Answer: A
Why: The maximum flow's value equals the maximum matching's size exactly, by construction. A value of 2 out of 3 possible Left nodes means the largest matching achievable with these edges pairs up only 2 of the 3 Left nodes; the third has no compatible, unused Right node.
Section
Section 6
Concept
Bipartite matching is just one example of a problem that looks like it needs its own separate algorithm, but turns out to be a flow problem in disguise once you find the right source, sink, and capacities.
Concept
This is the reassuring part: every one of those reductions inherits Edmonds-Karp's guarantee. Once a problem is reduced to max flow, it is solved in time polynomial in the size of the input, no matter how large the network gets.
That is not true of every problem you will meet this term. Flow sits on the fortunate side of a line that runs through the rest of the course.
Concept
Flow problems always yield to an efficient algorithm, but plenty of other problems that sound just as reasonable to state do not have any known efficient algorithm at all.
The rest of this course turns to exactly that gap: how to recognize a problem that likely has no efficient algorithm, a property called NP-completeness, and what to do about it when you meet one.
Explain it
Discussion prompt
Explain The bridge to NP-completeness to a student a year behind you. No notation, no jargon they have not met — and it still has to be true.
Hint: If your explanation needs a symbol they have never seen, you are describing the notation rather than the idea.
Answer:
Flow problems always yield to an efficient algorithm, but plenty of other problems that sound just as reasonable to state do not have any known efficient algorithm at all.
Intuition
What move should we make next?
Sixteen named moves, eighteen lessons, one final exam.
Close the deck. Write all sixteen from memory, in order, with a one-line description of each.
Then, for any proof from any lesson this term, you should be able to name the moves it used. If you can do that, you are not memorizing proofs any more.
_Look at your toolkit. Say a move number out loud before this slide advances._ A wrong guess is useful. A silent guess is not.
Analogy
Discussion prompt
Explain Decision point: account for the whole course by analogy to something with no CS3000 Algorithms in it at all — a queue, a recipe, a map, a bank balance, whatever fits. Then say where your analogy breaks.
Hint: An analogy that never breaks is not an analogy, it is the same idea wearing a hat. Find the seam — that is the part that is actually new.
Answer:
Sixteen named moves, eighteen lessons, one final exam.
Elimination
Eliminate the wrong options
What is the maximum flow from s to t in this network?
3 of these 4 are wrong. Strike them one at a time, and say what rules each one out before you strike the next. The survivor is the answer.
Survives elimination: A
Why: Send 2 along s-x-t and 2 along s-y-t (total 4), saturating x-t and s-y. One more augmenting path remains, s to x to y to t with bottleneck 1 (using the leftover residual capacity 1 on s-x and the untouched edge x-y and the leftover residual capacity 1 on y-t), bringing the total to 5. Now both edges leaving s, s-x and s-y, are saturated, so no augmenting path remains. This matches the cut capacity(s,x) + capacity(s,y) = 3 + 2 = 5.
Check
A new network: s to x (capacity 3), s to y (capacity 2), x to y (capacity 1), x to t (capacity 2), y to t (capacity 3).
| edge | capacity |
|---|---|
| s to x | 3 |
| s to y | 2 |
| x to y | 1 |
| x to t | 2 |
| y to t | 3 |
Check your understanding
What is the maximum flow from s to t in this network?
Answer: A
Why: Send 2 along s-x-t and 2 along s-y-t (total 4), saturating x-t and s-y. One more augmenting path remains, s to x to y to t with bottleneck 1 (using the leftover residual capacity 1 on s-x and the untouched edge x-y and the leftover residual capacity 1 on y-t), bringing the total to 5. Now both edges leaving s, s-x and s-y, are saturated, so no augmenting path remains. This matches the cut capacity(s,x) + capacity(s,y) = 3 + 2 = 5.
Pattern
Step through it
Step through Check yourself: a full max-flow computation one row at a time. What is driving the change, and what would the row after the last one be?
Concept
Moves added today:
Moves you reused today:
That is the full toolkit: 16 named moves, built across 18 lessons. Every proof in this course was some arrangement of them. Nothing on the final will need a seventeenth.
Full toolkit so far: #1 through #16.
Next session opens with you naming every one of these from memory, before any new material.
Counterexample
Discussion prompt
Next session opens with you naming every one of these from memory, before any new material.
That is stated as though it always holds. Do one of two things: produce a case where it fails, or say precisely what rules such a case out. "It just does" is not on the menu.
Hint: Hunt at the extremes first — zero, one, negative, empty, equal. If every extreme survives, the reason they survive is the proof.
Connect it up
Draw it
One page, no notation unless you need it: draw how these connect — Flow Networks: The Basics · Residual Graphs & Augmenting Paths · Ford-Fulkerson & Edmonds-Karp · The Max-Flow Min-Cut Theorem · Bipartite Matching as Flow · Beyond Flow. Put an arrow wherever one of them is what makes another possible, and label the arrow with why.
Recap
You can now read, build, and reason about flow networks from the ground up.
| Idea | The one thing to remember |
|---|---|
| Valid flow | Capacity limit and conservation, at every internal node |
| Residual graph | Forward = leftover capacity; backward = flow available to undo |
| Ford-Fulkerson / Edmonds-Karp | Augment until none remain; shortest path first stays fast |
| Max-flow min-cut | Maximum flow value equals minimum cut capacity, always |
Want this taught 1-on-1? Alexander tutors CS3000 Algorithms — $55/session, free consultation.