UNPKG

@algorithm.ts/isap

Version:
153 lines (149 loc) 4.65 kB
'use strict'; var queue = require('@algorithm.ts/queue'); class Isap { _cur = []; _cnt = []; _dist = []; _path = []; _edges = []; _G = []; _Q = new queue.CircularQueue({ capacity: 4 }); _N; _source; _sink; _maxflow; _edgesTot; _modifiedTimestamp; _resolvedTimestamp; constructor() { this._N = 0; this._source = -1; this._sink = -1; this._maxflow = 0; this._edgesTot = 0; this._modifiedTimestamp = 0; this._resolvedTimestamp = -1; } init(source, sink, n) { this._N = n; this._source = source; this._sink = sink; this._maxflow = 0; this._edgesTot = 0; this._modifiedTimestamp = 0; this._resolvedTimestamp = -1; this._cur.length = n; this._cnt.length = n; this._dist.length = n; this._path.length = n; this._G.length = n; this._Q.init(); this._Q.resize(n + 1); for (let i = 0; i < n; i++) this._G[i] = []; } addEdge(from, to, cap) { const { _G, _edges, _edgesTot } = this; _G[from].push(_edgesTot); _G[to].push(_edgesTot + 1); _edges[_edgesTot] = { from, to, cap, flow: 0 }; _edges[_edgesTot + 1] = { from: to, to: from, cap: 0, flow: 0 }; this._edgesTot += 2; this._modifiedTimestamp += 1; } maxflow() { if (this._resolvedTimestamp < this._modifiedTimestamp) { let { _maxflow } = this; const { _N, _source, _sink, _G, _edges, _dist, _path, _cur, _cnt } = this; _cur.fill(0, 0, _N); _cnt.fill(0, 0, _N); this._bfs(); for (let o = 0; o < _N; ++o) { if (_dist[o] < _N) _cnt[_dist[o]] += 1; } for (let o = _source; _dist[o] < _N;) { if (o === _sink) { _maxflow += this._augment(); o = _source; } let blocked = true; const g = _G[o]; for (let i = _cur[o], g = _G[o]; i < g.length; ++i) { const e = _edges[g[i]]; if (e.cap > e.flow && _dist[o] === _dist[e.to] + 1) { blocked = false; _cur[o] = i; _path[e.to] = g[i]; o = e.to; break; } } if (blocked) { let d = _N - 1; for (const x of g) { const e = _edges[x]; if (e.cap > e.flow && d > _dist[e.to]) d = _dist[e.to]; } if (--_cnt[_dist[o]] === 0) break; _dist[o] = d + 1; _cnt[d + 1] += 1; _cur[o] = 0; if (o !== _source) o = _edges[_path[o]].from; } } this._maxflow = _maxflow; this._resolvedTimestamp = this._modifiedTimestamp; } return this._maxflow; } mincut() { this.maxflow(); const results = []; const { _edges, _edgesTot } = this; for (let i = 0; i < _edgesTot; ++i) { const e = _edges[i]; if (e.cap > 0 && e.flow === e.cap) results.push(e); } return results; } _bfs() { const { _N, _sink, _G, _edges, _Q, _dist } = this; _dist.fill(-1, 0, _N); _Q.enqueue(_sink); _dist[_sink] = 0; while (_Q.size > 0) { const o = _Q.dequeue(); for (const i of _G[o]) { const e = _edges[i]; if (_dist[e.to] === -1 && e.cap === 0) { _dist[e.to] = _dist[o] + 1; _Q.enqueue(e.to); } } } } _augment() { let mif = Number.POSITIVE_INFINITY; const { _source, _sink, _edges, _path } = this; for (let o = _sink; o !== _source;) { const e = _edges[_path[o]]; const remainCap = e.cap - e.flow; if (mif > remainCap) mif = remainCap; o = e.from; } for (let o = _sink; o !== _source;) { const x = _path[o]; _edges[x].flow += mif; _edges[x ^ 1].flow -= mif; o = _edges[x].from; } return mif; } } exports.Isap = Isap;