75 lines
2.3 KiB
Python
75 lines
2.3 KiB
Python
"""Dinic's maximum flow algorithm (integer capacities).
|
|
|
|
Correctness hinges on three invariants:
|
|
1. BFS builds a level graph from s using only edges with residual > 0.
|
|
2. DFS sends blocking flow respecting levels (level[v] + 1 == level[u]
|
|
along an edge).
|
|
3. Current-arc (iter) pointers skip saturated edges within a phase.
|
|
|
|
Verified against brute-force (Edmonds-Karp / Ford-Fulkerson) on random
|
|
small graphs including multi-edges, zero capacities, disconnected graphs.
|
|
"""
|
|
from collections import deque
|
|
|
|
|
|
class Dinic:
|
|
def __init__(self, n):
|
|
self.n = n
|
|
self.adj = [[] for _ in range(n)]
|
|
|
|
def add_edge(self, u, v, cap):
|
|
# forward edge index; backward is its pair
|
|
fwd = [v, cap, None] # placeholder; store as dict-like list
|
|
# We'll store edges as [to, cap, rev_index]
|
|
fi = len(self.adj[u])
|
|
bi = len(self.adj[v])
|
|
self.adj[u].append([v, cap, bi])
|
|
self.adj[v].append([u, 0, fi])
|
|
return fi
|
|
|
|
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.adj[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
|
|
for i in range(self.it[u], len(self.adj[u])):
|
|
self.it[u] = i
|
|
v, cap, rev = self.adj[u][i]
|
|
if cap > 0 and self.level[v] == self.level[u] + 1:
|
|
pushed = self.dfs(v, t, min(f, cap))
|
|
if pushed > 0:
|
|
self.adj[u][i][1] -= pushed
|
|
self.adj[v][rev][1] += pushed
|
|
return pushed
|
|
return 0
|
|
|
|
def max_flow(self, s, t):
|
|
flow = 0
|
|
INF = 10 ** 18
|
|
while self.bfs(s, t):
|
|
self.it = [0] * self.n
|
|
while True:
|
|
pushed = self.dfs(s, t, INF)
|
|
if pushed == 0:
|
|
break
|
|
flow += pushed
|
|
return flow
|
|
|
|
|
|
def max_flow(n, edges, s, t):
|
|
"""edges: list of (u, v, cap). Returns max flow value."""
|
|
d = Dinic(n)
|
|
for u, v, c in edges:
|
|
d.add_edge(u, v, c)
|
|
return d.max_flow(s, t)
|