// Dinic below includes a full residual graph structure. This is the FF idea:
// Repeatedly find any s->t path in residual graph and augment by its bottleneck.
Uses BFS on the residual graph to get the shortest augmenting path in number of edges, guaranteeing O(n·m²) time.
// Dinic's algorithm implementation (adjacency list of edges with rev indices)
function Dinic(n) {
const level = Array(n).fill(0);
const it = Array(n).fill(0);
const G = Array.from({length: n}, () => []);
function addEdge(u, v, c) {
const a = { to: v, cap: c, rev: null };
const b = { to: u, cap: 0, rev: a };
a.rev = b; G[u].push(a); G[v].push(b);
}
function bfs(s, t) {
level.fill(-1); const q = []; level[s] = 0; q.push(s);
for (let qi = 0; qi < q.length; qi++) {
const u = q[qi];
for (const e of G[u]) if (e.cap > 0 && level[e.to] < 0) {
level[e.to] = level[u] + 1; q.push(e.to);
}
}
return level[t] >= 0;
}
function dfs(u, t, f) {
if (u === t) return f;
for (let i = it[u]; i < G[u].length; i++, it[u] = i) {
const e = G[u][i];
if (e.cap > 0 && level[e.to] === level[u] + 1) {
const ret = dfs(e.to, t, Math.min(f, e.cap));
if (ret > 0) { e.cap -= ret; e.rev.cap += ret; return ret; }
}
}
return 0;
}
function maxFlow(s, t) {
let flow = 0;
while (bfs(s, t)) {
it.fill(0);
for (;;) { const pushed = dfs(s, t, 1e18); if (!pushed) break; flow += pushed; }
}
return flow;
}
// Optional: retrieve min-cut after maxFlow by nodes with level >= 0 in last BFS from s
function minCutSet(s) {
// after running maxFlow, run bfs(s, t) without resetting residuals; nodes with level != -1 are on s-side
return level.map((lv, i) => lv !== -1 ? i : -1).filter(i => i !== -1);
}
return { addEdge, maxFlow, minCutSet };
}