QUICK START:HTMLCSSJavaScriptTypeScriptPythonSQLReactNext.jsNode.jsLinux & UbuntuKotlinSwiftC# / .NETJavaGoRustC++DSASystem DesignDevOpsCybersecurityAI / ML
Advanced 28 min readModule: Module 15: Advanced Graph Network Flows: Dinic's Algorithm

Network Flow Algorithms: Dinic's & Bipartite Matching

Solve complex network routing and assignment problems: Maximum Flow / Minimum Cut theorem, Residual graphs, Dinic's Algorithm using BFS Level Graphs and DFS Blocking Flows in O(V²E) time, and Hopcroft-Karp Bipartite Matching.

What You Will Learn in This Lesson

  • The Max-Flow Min-Cut Theorem and Ford-Fulkerson foundations
  • Why Edmonds-Karp is slow (O(V E²)) and how Dinic's algorithm optimizes flow to O(V² E)
  • Constructing BFS Level Graphs and pushing blocking flows via DFS with pointer pruning
  • Solving Maximum Bipartite Matching in O(E √V) with Hopcroft-Karp

Introduction & Core Concept

Network Flow algorithms model how resources (liquid in pipes, network packets in routers, traffic in road grids, tasks assigned to workers) can flow through a directed capacity-constrained graph from a Source (S) to a Sink (T). Dinic's algorithm is one of the most efficient Max-Flow algorithms in computer science: it builds a layered BFS Level Graph and pushes multiple Augmenting Paths simultaneously via DFS Blocking Flows.
WHY DOES THIS MATTER IN THE REAL WORLD?

Network flow algorithms power airline crew scheduling, ride-share dispatch matching (Uber/Lyft driver assignment), image segmentation in computer vision, and network routing throughput optimization.

Syntax & Structure

javascript
// Dinic's Flow Loop
while (bfs_build_level_graph()) {
while (flow = dfs_blocking_flow(s, t, INF)) max_flow += flow;
}

Implementing Dinic's Maximum Network Flow Algorithm

javascript
javascript
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
// Dinic's Maximum Network Flow Algorithm Implementation
class Edge {
constructor(to, cap, flow = 0, revIndex = 0) {
this.to = to;
this.cap = cap;
this.flow = flow;
this.revIndex = revIndex; // Index of reverse residual edge
}
}
class DinicMaxFlow {
constructor(numVertices) {
this.V = numVertices;
this.adj = Array.from({ length: numVertices }, () => []);
this.level = new Array(numVertices);
this.ptr = new Array(numVertices); // DFS edge pointer for pruning
}
addEdge(from, to, capacity) {
const forward = new Edge(to, capacity, 0, this.adj[to].length);
const backward = new Edge(from, 0, 0, this.adj[from].length);
this.adj[from].push(forward);
this.adj[to].push(backward);
}
// Step 1: BFS to build layered level graph
bfs(source, sink) {
this.level.fill(-1);
this.level[source] = 0;
const queue = [source];
while (queue.length > 0) {
const u = queue.shift();
for (const edge of this.adj[u]) {
if (edge.cap - edge.flow > 0 && this.level[edge.to] === -1) {
this.level[edge.to] = this.level[u] + 1;
queue.push(edge.to);
}
}
}
return this.level[sink] !== -1;
}
// Step 2: DFS to push blocking flow along level graph
dfs(u, sink, pushed) {
if (pushed === 0 || u === sink) return pushed;
for (let cid = this.ptr[u]; cid < this.adj[u].length; cid++) {
this.ptr[u] = cid;
const edge = this.adj[u][cid];
const tr = edge.to;
if (this.level[u] + 1 !== this.level[tr] || edge.cap - edge.flow === 0) continue;
const pushable = Math.min(pushed, edge.cap - edge.flow);
const flow = this.dfs(tr, sink, pushable);
if (flow > 0) {
edge.flow += flow;
this.adj[tr][edge.revIndex].flow -= flow;
return flow;
}
}
return 0;
}
computeMaxFlow(source, sink) {
let totalFlow = 0;
while (this.bfs(source, sink)) {
this.ptr.fill(0);
while (true) {
const pushed = this.dfs(source, sink, Infinity);
if (pushed === 0) break;
totalFlow += pushed;
}
}
return totalFlow;
}
}
// Verification Graph: Source (0) -> (1, 2) -> Sink (3)
const dinic = new DinicMaxFlow(4);
dinic.addEdge(0, 1, 10);
dinic.addEdge(0, 2, 10);
dinic.addEdge(1, 2, 2);
dinic.addEdge(1, 3, 4);
dinic.addEdge(2, 3, 9);
const maxFlow = dinic.computeMaxFlow(0, 3);
console.log("=== Dinic's Maximum Network Flow Algorithm ===");
console.log("Computed Maximum Flow:", maxFlow); // Expected: 13
console.log("✅ Optimal bottleneck capacity computed in O(V²E) time!");

Line-by-Line Technical Breakdown

1Bipartite Matching with Dinic: Any Maximum Bipartite Matching problem (e.g. matching N job applicants to M job vacancies) can be modeled as Max-Flow in O(E √V) time by creating a Source connected to all applicants with capacity 1, and connecting all jobs to a Sink with capacity 1.

Try It Yourself (Interactive Editor)

Modify the code in real-time and click Run to test live browser output and console logs.

Intelligent Code Runner & Live Sandbox[JAVASCRIPT]
JAVASCRIPT SOURCE EDITOR
Interactive Live Code

Common Mistakes & How to Avoid Them

#1: Omitting reverse residual edges with negative flow adjustments, preventing the algorithm from routing around suboptimal paths.

Without reverse residual edges, the flow network cannot 'push back' flow if a better global route is discovered later.

Incorrect / Antipattern
// Adding only forward edge without backward edge
Correct / Professional Solution
adj[from].push(forward); adj[to].push(backwardWithZeroCap);

Industry Best Practices & Professional Standards

  • Use Dinic's algorithm for general maximum flow networks.
  • Use Hopcroft-Karp when specifically solving Maximum Bipartite Matching for O(E √V) performance.
  • Reset edge pointers (`ptr.fill(0)`) before each DFS blocking flow phase.

Lesson Summary & Core Takeaways

  • Network Flow algorithms calculate maximum capacity routing from Source to Sink.
  • Dinic's algorithm combines BFS Level Graphs with DFS Blocking Flows in O(V² E).
  • Max-Flow Min-Cut theorem solves network routing, matching, and image segmentation problems.