maxflow

Maximum Flow — Edmonds-Karp Algorithm

Problem

Given a directed graph G=(V,E)G = (V, E) with source ss and sink tt, each edge (u,v)(u,v) has capacity c(u,v)c(u,v). Find the maximum flow from ss to tt respecting capacity constraints.

maximizevf(s,v)subject to0f(u,v)c(u,v)\text{maximize} \quad \sum_{v} f(s,v) \quad \text{subject to} \quad 0 \le f(u,v) \le c(u,v)

Edmonds-Karp = Ford-Fulkerson with BFS for shortest augmenting paths. Guarantees O(VE2)O(VE^2).

Algorithm Walkthrough

Step 1 / 15

Key Insight: Residual Graph

The residual graph includes:

Iteration 4 used a reverse edge to reroute: ACA \to C flow decreased from 7 to 6, redirecting 1 unit through CDTC \to D \to T.

Complexity

Implementation (Dinic's)

from collections import deque

class Dinic:
    def __init__(self, n):
        self.n = n
        self.graph = [[] for _ in range(n)]

    def add_edge(self, u, v, cap):
        self.graph[u].append([v, cap, len(self.graph[v])])
        self.graph[v].append([u, 0, len(self.graph[u]) - 1])

    def bfs(self, s, t):
        self.level = [-1] * self.n
        self.level[s] = 0
        q = deque([s])
        while q:
            u = q.popleft()
            for v, cap, _ in self.graph[u]:
                if cap > 0 and self.level[v] < 0:
                    self.level[v] = self.level[u] + 1
                    q.append(v)
        return self.level[t] >= 0

    def dfs(self, u, t, f):
        if u == t:
            return f
        while self.iter[u] < len(self.graph[u]):
            e = self.graph[u][self.iter[u]]
            v, cap, rev = e
            if cap > 0 and self.level[v] == self.level[u] + 1:
                d = self.dfs(v, t, min(f, cap))
                if d > 0:
                    e[1] -= d
                    self.graph[v][rev][1] += d
                    return d
            self.iter[u] += 1
        return 0

    def max_flow(self, s, t):
        flow = 0
        while self.bfs(s, t):
            self.iter = [0] * self.n
            while True:
                f = self.dfs(s, t, float('inf'))
                if f == 0:
                    break
                flow += f
        return flow