Network Flow: Max-Flow, Min-Cut
Max Flow ও Min Cut
1. The Big Idea — Flow in Networks
Imagine a pipeline network from a water source s in Sylhet to a sink t in Dhaka. Each pipe segment has a maximum capacity in litres per second. The question: what is the largest steady flow you can push from s to t? That is the max-flow problem — and it is one of the most powerful modelling tools in all of algorithms.
2. Formal Definitions — Flow, Capacity, Cut
A flow network is a directed graph G = (V, E) with a non-negative capacity c(u,v) on each edge, plus a source s and sink t. A flow f(u,v) assigns a value to every edge satisfying:
- Capacity: 0 ≤ f(u,v) ≤ c(u,v)
- Conservation: for every internal node v, total in = total out
The value of the flow is the net flow leaving s (equivalently, entering t). An s-t cut partitions V into two sets S (containing s) and T (containing t); its capacity is the sum of capacities of edges crossing from S to T.
3. Residual Graph & Augmenting Paths
Given a current flow f, the residual capacity of edge (u,v) is
cf(u,v) = c(u,v) − f(u,v). The residual graph also contains
a back-edge (v,u) with capacity equal to the current flow f(u,v) — this lets
future iterations cancel earlier choices.
An augmenting path is any s-to-t path in the residual graph with positive capacity along every edge. The bottleneck is the smallest residual capacity on that path; pushing that much flow strictly increases the total.
c(u,v) − f(u,v)। সাথে একটি back-edge (v,u) থাকে capacity f(u,v) — যা পরবর্তীতে আগের সিদ্ধান্ত বদলাতে সাহায্য করে। Residual graph-এ s থেকে t পর্যন্ত positive capacity-র যেকোনো path-ই augmenting path। সেই path-এর সর্বনিম্ন capacity (bottleneck) পরিমাণ flow push করলে মোট flow বাড়ে।
4. Edmonds-Karp — BFS for Augmenting Paths
Edmonds-Karp is Ford-Fulkerson with one rule: always pick the shortest augmenting path (fewest edges) by BFS. This guarantees O(VE²) total time, independent of capacity values — a huge improvement.
#include <bits/stdc++.h>
using namespace std;
// Edmonds-Karp max-flow on a 6-node network: 0=s, 5=t.
const int N = 6;
int cap[N][N], flow[N][N];
int bfs(int s, int t, vector<int>& parent) {
fill(parent.begin(), parent.end(), -1);
parent[s] = s;
queue<pair<int,int>> q;
q.push({s, INT_MAX});
while (!q.empty()) {
auto [u, f] = q.front(); q.pop();
for (int v = 0; v < N; ++v) {
int resid = cap[u][v] - flow[u][v];
if (parent[v] == -1 && resid > 0) {
parent[v] = u;
int nf = min(f, resid);
if (v == t) return nf;
q.push({v, nf});
}
}
}
return 0;
}
int maxflow(int s, int t) {
int total = 0, push;
vector<int> parent(N);
while ((push = bfs(s, t, parent)) > 0) {
total += push;
int v = t;
while (v != s) {
int u = parent[v];
flow[u][v] += push;
flow[v][u] -= push;
v = u;
}
}
return total;
}
int main() {
// Build the network from Figure 31.1: nodes 0..5 = s,a,b,c,d,t
cap[0][1] = 10; cap[0][2] = 10;
cap[1][3] = 9; cap[1][4] = 2;
cap[2][4] = 10;
cap[3][5] = 10; cap[4][5] = 10;
cout << "Max flow s -> t = " << maxflow(0, 5) << "\n";
}
Expected output: Max flow s -> t = 18 — matching the min-cut from Figure 31.1.
5. The Max-Flow Min-Cut Theorem
Theorem (Ford-Fulkerson, 1956). In any flow network the maximum flow value equals the minimum s-t cut capacity.
- Every flow ≤ every cut (each unit of flow must cross the cut once net-positively).
- Run Edmonds-Karp until no augmenting path exists. Let S = nodes reachable from s in the final residual graph; T = V \ S. Then t ∈ T (else a path would exist).
- Every edge from S to T in the original graph is saturated (f = c) and every back-edge from T to S has zero flow. So flow value = capacity of cut (S,T) = min-cut. ∎
6. Dinic's Algorithm — A Faster Alternative
Dinic (1970) uses level graphs (BFS layers) and pushes flow along multiple shortest paths in one phase using DFS with blocking flow. Its complexity is O(V² E) in general, O(E √V) on unit-capacity graphs (perfect for bipartite matching), and very fast in practice — usually 10×–100× faster than Edmonds-Karp.
| Algorithm | Complexity | When to use |
|---|---|---|
| Ford-Fulkerson (DFS) | O(E · max-flow) | Tiny graphs, integer capacities only |
| Edmonds-Karp (BFS) | O(VE²) | Easy to code, n < 500 |
| Dinic | O(V²E), O(E√V) unit cap | Contest standard, n ≤ 5000 |
| Push-Relabel | O(V²√E) | Very large dense graphs |
7. Bipartite Matching as Max-Flow
Given a bipartite graph (left set L, right set R, edges between them), a matching is a set of edges with no shared endpoint. To find the maximum matching size, build a flow network:
- Add super-source s with edges s → l (capacity 1) for every l ∈ L.
- Keep all bipartite edges l → r with capacity 1.
- Add super-sink t with edges r → t (capacity 1) for every r ∈ R.
- Maximum flow value = maximum matching size.
#include <bits/stdc++.h>
using namespace std;
// Bipartite matching via Hungarian-style augmenting path (a simplified Edmonds-Karp).
// Left side has L students, right side has R job slots in a Bangladesh job-fair.
int L, R;
vector<vector<int>> adj; // adj[u] = right-side neighbours of left u
vector<int> matchR; // matchR[r] = left node matched to r, or -1
vector<bool> visited;
bool tryAugment(int u) {
for (int v : adj[u]) {
if (visited[v]) continue;
visited[v] = true;
if (matchR[v] == -1 || tryAugment(matchR[v])) {
matchR[v] = u;
return true;
}
}
return false;
}
int maxMatching() {
matchR.assign(R, -1);
int total = 0;
for (int u = 0; u < L; ++u) {
visited.assign(R, false);
if (tryAugment(u)) ++total;
}
return total;
}
int main() {
L = 4; R = 4;
adj.assign(L, {});
// Students 0..3, jobs 0..3. Edges = a student is qualified for a job.
adj[0] = {0, 1};
adj[1] = {0, 2};
adj[2] = {1, 3};
adj[3] = {2, 3};
cout << "Max matching = " << maxMatching() << "\n";
for (int r = 0; r < R; ++r)
cout << "Job " << r << " -> Student " << matchR[r] << "\n";
}
8. Where Max-Flow Lives (বাস্তব প্রয়োগ)
Job assignment, Bangladesh medical-college admission slot allocation।
Foreground/background separation via min-cut।
Choose profitable projects with prerequisite dependencies।
Has a team been mathematically eliminated from the title race?
Shipping goods through capacity-limited routes।
Edge-disjoint paths via Menger's theorem।
9. Practice Problems
-
Maximum bipartite matching: 5 students applying to 5 universities. Find max assignment.৫ জন ছাত্র ৫টি বিশ্ববিদ্যালয়ে আবেদন করেছে। সর্বাধিক বরাদ্দ বের করুন।
✨ Show Answer (উত্তর দেখুন)
ans1.cpp#include <bits/stdc++.h> using namespace std; int L=5, R=5; vector<vector<int>> adj; vector<int> matchR; vector<bool> vis; bool aug(int u){for(int v:adj[u]){if(vis[v])continue;vis[v]=1;if(matchR[v]==-1||aug(matchR[v])){matchR[v]=u;return 1;}}return 0;} int main(){ adj.assign(L,{}); adj[0]={0,1}; adj[1]={1,2}; adj[2]={0,3}; adj[3]={2,4}; adj[4]={3,4}; matchR.assign(R,-1); int tot=0; for(int u=0;u<L;++u){vis.assign(R,0);if(aug(u))++tot;} cout<<"Matching = "<<tot<<"\n"; } -
Minimum vertex cover in a bipartite graph via König's theorem (= max matching size).König's theorem অনুযায়ী bipartite graph-এ minimum vertex cover = max matching। প্রমাণ করুন।
✨ Show Answer (উত্তর দেখুন)
Answer: König's theorem states that in any bipartite graph, the size of a minimum vertex cover equals the size of a maximum matching. Construction: after computing the matching, let U = unmatched left nodes. Run an alternating BFS from U (alternating non-matching/matching edges). Let Z = visited nodes. Then the cover is (Left \ Z) ∪ (Right ∩ Z); its size equals the matching.
König-এর উপপাদ্য বলে — bipartite graph-এ minimum vertex cover-এর আকার = maximum matching-এর আকার। নির্মাণ: matching বের করে unmatched বাঁ-পাশের nodes থেকে alternating BFS চালান, পৌঁছানো nodes Z হলে cover = (Left \ Z) ∪ (Right ∩ Z)।
-
Project selection: 4 projects with given profits and prerequisite tasks with given costs. Pick a subset to maximise profit minus cost.৪টি project আছে — profit আছে, কিন্তু prerequisite task-এ খরচ আছে। সর্বাধিক net profit-এর জন্য কোন project বেছে নেবেন?
✨ Show Answer (উত্তর দেখুন)
Reduction: Build a graph: source s → each project p with capacity = profit(p); each task t → sink t0 with capacity = cost(t); each project → its required tasks with capacity ∞. Then
answer = total_profit − min-cut. The min-cut splits projects into "do" (source side) and "skip" (sink side), and includes the cost of every task needed by selected projects.Reduction: source থেকে প্রতিটি project-এ profit capacity, প্রতিটি task থেকে sink-এ cost capacity, project থেকে required task-এ ∞ capacity। উত্তর = total_profit − min-cut।
-
Implement min-cut between s and t on the network from Figure 31.1 — print which nodes lie on the s-side.Figure 31.1-এর network-এ s ও t-এর মধ্যে min-cut বের করুন এবং s-পাশের nodes প্রিন্ট করুন।
✨ Show Answer (উত্তর দেখুন)
ans4.cpp#include <bits/stdc++.h> using namespace std; const int N=6; int cap[N][N], flow[N][N]; int bfs(int s,int t,vector<int>& p){fill(p.begin(),p.end(),-1);p[s]=s;queue<pair<int,int>> q;q.push({s,INT_MAX});while(!q.empty()){auto[u,f]=q.front();q.pop();for(int v=0;v<N;++v){int r=cap[u][v]-flow[u][v];if(p[v]==-1&&r>0){p[v]=u;int nf=min(f,r);if(v==t)return nf;q.push({v,nf});}}}return 0;} int main(){ cap[0][1]=10;cap[0][2]=10;cap[1][3]=9;cap[1][4]=2;cap[2][4]=10;cap[3][5]=10;cap[4][5]=10; vector<int> p(N); int mf=0,push; while((push=bfs(0,5,p))>0){mf+=push;int v=5;while(v!=0){int u=p[v];flow[u][v]+=push;flow[v][u]-=push;v=u;}} // Now find S = reachable from 0 in residual vector<bool> vis(N,0);queue<int> q;q.push(0);vis[0]=1; while(!q.empty()){int u=q.front();q.pop();for(int v=0;v<N;++v)if(!vis[v]&&cap[u][v]-flow[u][v]>0){vis[v]=1;q.push(v);}} cout<<"Max flow = "<<mf<<"\nS-side nodes: "; for(int i=0;i<N;++i)if(vis[i])cout<<i<<" "; cout<<"\n"; } -
Baseball elimination preview: with current standings and remaining games, decide if a team is eliminated.Cricket-এর Premier League-এ বর্তমান অবস্থান ও বাকি ম্যাচ থেকে কোনো দল title race থেকে eliminated কিনা — কীভাবে max-flow দিয়ে বের করবেন?
✨ Show Answer (উত্তর দেখুন)
Idea: For target team x, give every other team y the maximum wins they can have without eliminating x:
w[x] + r[x] − w[y]. Build a network: source s → each remaining game (i,j) with capacity g(i,j); each game → its two teams with capacity ∞; each team y → sink t with capacity (w[x]+r[x]−w[y]). If the max-flow saturates all source edges (= total remaining games among teams ≠ x), x can still win the title; otherwise x is eliminated. Used by ESPN-style standings as well as BPL projection systems.প্রতিটি অন্য দলকে x-কে না হারানোর সর্বোচ্চ জয় দিন। source → remaining game → দুই দল → sink — এই network-এ max-flow source-এর সব edge saturate করলে x এখনো জিততে পারে; নইলে eliminated।
Summary — Module 31
Network flow models any "amount-routed-through-capacity" problem. Ford-Fulkerson is the framework; Edmonds-Karp gives O(VE²) by always picking shortest augmenting paths via BFS; Dinic's level graph + blocking flow gives O(V²E) and O(E√V) for unit-capacity graphs. The Max-Flow Min-Cut theorem is the bridge that turns flow problems into cut problems and vice versa, making bipartite matching, project selection, image segmentation and sports elimination all instances of one idea.