MaxFlow
最大フロー問題 を解くライブラリです。
コンストラクタ
var graph = init_mf_graph[Cap](n:int)
n
頂点 $0$ 辺のグラフを作る。Cap
は容量の型。
制約
- $0 \leq n \leq 10^8$
Cap
は int
, ll
計算量
add_edge
graph.add_edge(src:int, dst:int, cap:Cap):int
from
からto
へ最大容量cap
、流量 $0$ の辺を追加し、何番目に追加された辺かを返す。
制約
- $0 \leq \mathrm{from}, \mathrm{to} \lt n$
- $0 \leq \mathrm{cap}$
計算量
flow
(1) graph.flow(s:int, t:int):Cap
(2) graph.flow(s:int, t:int, flow_limit:Cap):Cap
- (1) 頂点 $s$ から $t$ へ流せる限り流し、流せた量を返す。
- (2) 頂点 $s$ から $t$ へ流量 $flow_limit$ に達するまで流せる限り流し、流せた量を返す。
- 複数回呼ぶことも可能で、その時の挙動は Appendix を参照してください。
制約
計算量
$m$ を追加された辺数として
- $O(\min(n^{\frac{2}{3}}m, m^{\frac{3}{2}}))$ (辺の容量がすべて $1$ の時)
- $O(n^2 m)$
min_cut
graph.min_cut(s:int):seq[bool]
長さ $n$ のvectorを返す。$i$ 番目の要素には、頂点 $s$ から $i$ へ残余グラフで到達可能なとき、またその時のみ true
を返す。flow(s, t)
をflow_limitなしでちょうど一回呼んだ後に呼ぶと、返り値は $s$, $t$ 間のmincutに対応します。詳細な挙動は Appendix を参照してください。
計算量
$m$ を追加された辺数として
get_edge / edges
edge_info[Cap] = object
src, dst:int
cap, flow:Cap
(1) graph.get_edge(i:int):edge_info[Cap]
(2) graph.edges():seq[edge_info[Cap]]
- 今の内部の辺の状態を返す
- 辺の順番はadd_edgeで追加された順番と同一
制約
計算量
$m$ を追加された辺数として
change_edge
graph.change_cap(i:int, new_cap:Cap, new_flow:Cap):void
$i$ 番目に変更された辺の容量、流量をnew_cap
, new_flow
に変更する。他の辺の容量、流量は変更しない。詳細は Appendix を参照してください
制約
- $0 \leq \mathrm{newflow} \leq \mathrm{newcap}$
計算量
使用例
include atcoder/header
import atcoder/maxflow
let n, m = nextInt()
var grid = newSeqWith(n, nextString())
# generate (s -> even grid -> odd grid -> t) graph
# grid(i, j) correspond to vertex (i * m + j)
var g = initMFGraph[int](n * m + 2)
let
s = n * m
t = n * m + 1;
# s -> even / odd -> t
for i in 0..<n:
for j in 0..<m:
if grid[i][j] == '#': continue
let v = i * m + j
if (i + j) mod 2 == 0:
g.add_edge(s, v, 1)
else:
g.add_edge(v, t, 1)
# even -> odd
for i in 0..<n:
for j in 0..<m:
if (i + j) mod 2 == 1 or grid[i][j] == '#': continue
let v0 = i * m + j
if i != 0 and grid[i - 1][j] == '.':
let v1 = (i - 1) * m + j
g.add_edge(v0, v1, 1)
if j != 0 and grid[i][j - 1] == '.':
let v1 = i * m + (j - 1)
g.add_edge(v0, v1, 1)
if i + 1 < n and grid[i + 1][j] == '.':
let v1 = (i + 1) * m + j
g.add_edge(v0, v1, 1)
if j + 1 < m and grid[i][j + 1] == '.':
let v1 = i * m + (j + 1)
g.add_edge(v0, v1, 1)
echo g.flow(s, t)
let edges = g.edges()
for e in edges:
if e.src == s or e.dst == t or e.flow == 0: continue
let
i0 = e.src div m
j0 = e.src mod m
i1 = e.dst div m
j1 = e.dst mod m
if i0 == i1 + 1:
grid[i1][j1] = 'v'; grid[i0][j0] = '^'
elif j0 == j1 + 1:
grid[i1][j1] = '>'; grid[i0][j0] = '<'
elif i0 == i1 - 1:
grid[i0][j0] = 'v'; grid[i1][j1] = '^'
else:
grid[i0][j0] = '>'; grid[i1][j1] = '<'
echo grid.join("\n")