最大フロー問題を解くアルゴリズムの Dinic’s Algorithm
概要
最大流問題は、有向グラフ \(G = (V, E)\) の各辺 \(e \in E\) に容量 \(c(u, v)\) がついており、このグラフ上のsourceからsinkへ流せる流量を求める問題である。
最大フロー最小カット定理が成り立つため、最小カット問題も解くことができる。
Dinic’s Algorithm
Ford-Fulkerson algorithmよりも早い最大流アルゴリズム。 以下の処理をフローを流しきるまで繰り返す。
-
BFSでsourceから各頂点までの距離(\(level\))を計算
-
DFSで、sourceからの距離が遠くなるようなパスを見つけ、フローを流す
計算量
\(O(|V|^2|E|)\)
実装
# Dinic's algorithm
from collections import deque
class Dinic:
def __init__(self, N):
self.N = N
self.G = [[] for i in range(N)]
def add_edge(self, fr, to, cap):
forward = [to, cap, None]
forward[2] = backward = [fr, 0, forward]
self.G[fr].append(forward)
self.G[to].append(backward)
def add_multi_edge(self, v1, v2, cap1, cap2):
edge1 = [v2, cap1, None]
edge1[2] = edge2 = [v1, cap2, edge1]
self.G[v1].append(edge1)
self.G[v2].append(edge2)
def bfs(self, s, t):
self.level = level = [None]*self.N
deq = deque([s])
level[s] = 0
G = self.G
while deq:
v = deq.popleft()
lv = level[v] + 1
for w, cap, _ in G[v]:
if cap and level[w] is None:
level[w] = lv
deq.append(w)
return level[t] is not None
def dfs(self, v, t, f):
if v == t:
return f
level = self.level
for e in self.it[v]:
w, cap, rev = e
if cap and level[v] < level[w]:
d = self.dfs(w, t, min(f, cap))
if d:
e[1] -= d
rev[1] += d
return d
return 0
def flow(self, s, t):
flow = 0
INF = 10**9 + 7
G = self.G
while self.bfs(s, t):
*self.it, = map(iter, self.G)
f = INF
while f:
f = self.dfs(s, t, INF)
flow += f
return flow
Verified
Verified (旧実装)
-
CodeChef: "CodeChef June Challenge 2018 - Binary Board": source (Python3, 7.84sec)
-
AtCoder: "AtCoder Regular Contest 085 - E問題: MUL": source (Python3, 23ms)
-
AtCoder: "天下一プログラマーコンテスト2015予選A - C問題: 天下一美術館": source (Python2, 1417ms)
-
AtCoder: "東京工業大学プログラミングコンテスト2015 - L問題: グラフ色ぬり": source (Python2, 74ms)
-
AOJ: "GRL_6_A: Network Flow - Maximum Flow": source (Python2, 0.01sec), source (Python3, 0.03sec)