Network Flow: Max-Flow, Min-Cut

Max Flow ও Min Cut

Read: ~45 min Advanced 5 practice problems Live C++ runner

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.

ধরা যাক Sylhet-এর একটি জল-উৎস s থেকে Dhaka-র একটি sink t-এ পাইপের নেটওয়ার্ক আছে। প্রতিটি পাইপের নির্দিষ্ট capacity (লিটার/সেকেন্ড)। প্রশ্ন — সর্বাধিক কত flow পাঠানো সম্ভব? এটিই max-flow problem — algorithms-এর সবচেয়ে শক্তিশালী modelling tool-গুলোর একটি।
Module insight Max-flow = min-cut — Computer Science-এর সবচেয়ে কাব্যিক উপপাদ্য। অসংখ্য সমস্যা এতে রূপান্তর করা যায় — bipartite matching, project selection, image segmentation, baseball elimination, এমনকি assignment problem।

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.

একটি flow network মানে directed graph যেখানে প্রতিটি edge-এ capacity আছে, সাথে একটি source s এবং sink t। প্রতিটি edge-এর flow capacity-র চেয়ে বেশি হবে না, এবং প্রতিটি internal node-এ যা ঢোকে তাই বের হয় (conservation)। একটি s-t cut মানে nodes-কে দুই ভাগে ভাগ করা — একদিকে s, অন্যদিকে t — এবং S থেকে T-গামী edge-গুলোর capacity-র যোগফলই cut-এর capacity।
s a b c d t 10/10 10/8 9/9 10/8 2/1 10/10 10/7 min-cut = 9 + 1 + 8 = 18 Figure 31.1 — A 6-node flow network. Each label shows capacity / flow. The dashed red curve is the min-cut; max-flow value 18 = min-cut capacity 18.

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.

বর্তমান flow f-এর residual graph-এ প্রতিটি edge-এর অবশিষ্ট capacity হলো 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 বাড়ে।
Ford-Fulkerson method — repeat: (1) find any augmenting path; (2) push bottleneck flow; until no path exists. Termination is guaranteed for integer capacities, but a bad path choice can be exponential.

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.

Edmonds-Karp = Ford-Fulkerson + একটি নিয়ম: সর্বদা BFS দিয়ে সবচেয়ে ছোট augmenting path বেছে নিন। এতে মোট সময় O(VE²) — capacity-র মান নির্বিশেষে।
edmonds_karp.cpp
#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.

Sketch of proof.
  1. Every flow ≤ every cut (each unit of flow must cross the cut once net-positively).
  2. 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).
  3. 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. ∎
উপপাদ্য: যেকোনো flow network-এ সর্বাধিক flow = সর্বনিম্ন s-t cut capacity। প্রমাণের সারাংশ — (১) flow ≤ যেকোনো cut, (২) Edmonds-Karp শেষ হলে residual graph-এ s থেকে পৌঁছানো nodes-এর সেট S; t সেখানে নেই, (৩) S থেকে T-গামী সব edge পূর্ণ, T থেকে S-গামী সব edge শূন্য — তাই flow = 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.

Dinic-এর algorithm BFS দিয়ে level graph তৈরি করে, তারপর DFS দিয়ে blocking flow push করে। জটিলতা O(V²E), unit-capacity-তে O(E√V) — bipartite matching-এ দারুণ। বাস্তবে Edmonds-Karp-এর চেয়ে ১০–১০০ গুণ দ্রুত।
AlgorithmComplexityWhen to use
Ford-Fulkerson (DFS)O(E · max-flow)Tiny graphs, integer capacities only
Edmonds-Karp (BFS)O(VE²)Easy to code, n < 500
DinicO(V²E), O(E√V) unit capContest standard, n ≤ 5000
Push-RelabelO(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.
Bipartite graph-এ সর্বাধিক matching খুঁজতে — super-source s যোগ করুন বাঁ পাশের প্রতিটি node-এ capacity 1 edge দিয়ে; ডান পাশের প্রতিটি node থেকে super-sink t-তে capacity 1 edge; মাঝের সব edge capacity 1। তারপর s-t max-flow চালান — উত্তরই হলো maximum matching।
bipartite_match.cpp
#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";
}
Pitfall — for general (non-bipartite) matching, max-flow does NOT work; you need Edmonds' blossom algorithm. Bipartite is the special case that reduces nicely.

8. Where Max-Flow Lives (বাস্তব প্রয়োগ)

Bipartite matching
Job assignment, Bangladesh medical-college admission slot allocation।
Image segmentation
Foreground/background separation via min-cut।
Project selection
Choose profitable projects with prerequisite dependencies।
Sports elimination
Has a team been mathematically eliminated from the title race?
Transportation
Shipping goods through capacity-limited routes।
Network reliability
Edge-disjoint paths via Menger's theorem।

9. Practice Problems

প্রতিটি প্রশ্নের সাথে Show Answer বাটনে runnable C++ কোড আছে। আগে নিজে চেষ্টা করুন।
  1. 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";
    }
  2. 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)।

  3. 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।

  4. 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";
    }
  5. 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.

Network flow এমন যেকোনো সমস্যা মডেল করে যেখানে capacity দিয়ে কিছু পাঠানো হয়। Ford-Fulkerson হলো framework, Edmonds-Karp BFS দিয়ে O(VE²), Dinic O(V²E) এবং unit-capacity-তে O(E√V)। Max-Flow Min-Cut উপপাদ্যই bipartite matching, project selection, image segmentation, sports elimination — সব সমস্যা একই idea-তে রূপান্তরিত করে।

Next Module → Greedy Algorithms — কখন greedy কাজ করে এবং কখন প্রতারণা করে।