Dinic's algorithm computes the maximum flow through a network — the most water you can push from a source S to a sink T given per-pipe capacity limits. It is the fast, interview-friendly upgrade over plain Ford–Fulkerson, and its trick is a clean two-phase loop: BFS to build levels, then DFS to push a blocking flow.
Problem. Given a directed graph where each edge has a capacity, find the maximum total flow from
source S to sink T. Flow on an edge cannot exceed its capacity, and at every node (except S and
T) flow in must equal flow out.
Example network: S->A=3, S->B=2, A->B=1, A->T=2, B->T=3. The maximum flow is 4
(push 2 along S->A->T and 2 along S->B->T).
The slow way first
Plain Ford–Fulkerson finds one augmenting path at a time (any path with spare capacity), pushes flow along it, and repeats. It works, but it can waste effort: it may walk long, winding paths and, with awkward capacities, take a number of iterations that depends on the capacity values themselves — far too many.
The question to ask: can I find many augmenting paths at once, and only along the shortest routes? That is exactly what Dinic does.
The idea: BFS levels, then a blocking flow
Repeat two phases until you cannot reach the sink:
- BFS phase. From
S, run BFS on the residual graph and give every node a level = its distance fromS. IfTgets no level, stop — no more flow is possible. - DFS phase. Push flow with DFS, but only along level-respecting edges: an edge may carry flow only if it goes from level
Lto levelL+1. Keep pushing paths until none remain. The result is a blocking flow for these levels.
Restricting DFS to level-increasing edges is the key: paths can only get longer over the phases, which bounds the number of phases and makes the whole thing fast.
Walk through it
Step through the animation. Phase 1: BFS labels S=0, A=1, B=1, T=2. DFS pushes 2 along S->A->T, then 2 along S->B->T — running total 4. Phase 2: BFS runs again on what capacity is left, but T can no longer be reached, so we stop and return 4.
Pseudocode
total = 0
repeat:
level = BFS from S # distance of each node from S
if T has no level: stop # sink unreachable -> done
repeat:
pushed = DFS from S to T, following only level L -> L+1 edges
if pushed == 0: break # blocking flow complete
total += pushed
return totalThe Python solution
def dinic(graph, s, t):
total = 0
while True:
level = bfs(graph, s) # assign distance levels
if level[t] is None: # sink unreachable
break
while True:
pushed = dfs(graph, s, t, INF, level)
if pushed == 0:
break
total += pushed # add this path's flow
return totaltotalaccumulates the maximum flow across all phases.bfsreturns alevelmap (distance froms); it only follows residual edges with spare capacity.- Line 5 is the stopping test — if
Tgot no level, BFS could not reach it, so no more flow exists. - The inner loop calls
dfs, which pushes flow only along edges going from levelLto levelL+1, and returns the amount pushed. - When
dfsreturns0, the blocking flow for these levels is done; we run BFS again to relabel.
Complexity
| Case | Time | Notes |
|---|---|---|
| General graphs | O(V^2 * E) (moderate) | at most V BFS phases |
| Unit-capacity graphs | O(E * sqrt(V)) (moderate) | e.g. bipartite matching |
O(V + E) (moderate)Each phase strictly increases the BFS distance to T, so there are at most V phases; each phase's blocking flow costs O(V * E). That O(V^2 * E) bound is independent of the capacity values — a big win over plain Ford–Fulkerson.
When this pattern shows up
Max-flow is the hidden engine behind many problems: bipartite matching, edge-disjoint paths, project selection, and min-cut. If a problem reduces to "route as much as possible subject to limits," model it as a flow network and run Dinic.
The DFS must follow level-respecting edges only (L -> L+1). If you let DFS wander to same-level or
backward edges, you lose the distance-increase guarantee and the phase bound — and you can loop forever.
Practice
After Phase 1 pushes 2 along S->A->T and 2 along S->B->T, why does Phase 2's BFS fail to reach T?
1. What does the BFS phase compute?
2. Which edges may the DFS phase push flow along?
3. When does the algorithm stop?
4. Why is Dinic faster than plain Ford-Fulkerson here?