UNPKG

@algorithm.ts/mcmf

Version:
131 lines (127 loc) 4.08 kB
'use strict'; var queue = require('@algorithm.ts/queue'); const DEFAULT_INF = Math.floor(Number.MAX_SAFE_INTEGER / 2); class Mcmf { _INF; _inq = []; _dist = []; _path = []; _edges = []; _G = []; _Q = new queue.CircularQueue({ capacity: 4 }); _N; _source; _sink; _maxflow; _mincost; _edgesTot; _modifiedTimestamp; _resolvedTimestamp; constructor(options = {}) { const { INF = DEFAULT_INF } = options; this._INF = INF; this._N = 0; this._source = -1; this._sink = -1; this._maxflow = 0; this._mincost = 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._mincost = 0; this._edgesTot = 0; this._modifiedTimestamp = 0; this._resolvedTimestamp = -1; this._inq.length = n; this._dist.length = n; this._path.length = n; this._G.length = n; this._inq.fill(false, 0, n); this._Q.init(); this._Q.resize(n + 1); for (let i = 0; i < n; i++) this._G[i] = []; } addEdge(from, to, cap, cost) { const { _G, _edges, _edgesTot } = this; _G[from].push(_edgesTot); _G[to].push(_edgesTot + 1); _edges[_edgesTot] = { from, to, cap, flow: 0, cost }; _edges[_edgesTot + 1] = { from: to, to: from, cap: 0, flow: 0, cost: -cost }; this._edgesTot += 2; this._modifiedTimestamp += 1; } minCostMaxFlow() { if (this._resolvedTimestamp < this._modifiedTimestamp) { let { _maxflow, _mincost } = this; const { _INF, _source, _sink, _edges, _dist, _path } = this; while (this._bellmanFord()) { let mif = _INF; 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; } _maxflow += mif; _mincost += mif * _dist[_sink]; } this._maxflow = _maxflow; this._mincost = _mincost; this._resolvedTimestamp = this._modifiedTimestamp; } return { mincost: this._mincost, maxflow: this._maxflow }; } mincut() { void this.minCostMaxFlow(); 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; } _bellmanFord() { const { _INF, _N, _source, _sink, _G, _edges, _Q, _dist, _path, _inq } = this; _dist.fill(_INF, 0, _N); _Q.enqueue(_source); _dist[_source] = 0; _inq[_source] = true; while (_Q.size > 0) { const o = _Q.dequeue(); for (let i = 0, g = _G[o]; i < g.length; ++i) { const x = g[i]; const e = _edges[x]; if (e.cap === e.flow) continue; const candidateDist = _dist[o] + e.cost; if (_dist[e.to] > candidateDist) { _dist[e.to] = candidateDist; _path[e.to] = x; if (_inq[e.to]) continue; _inq[e.to] = true; _Q.enqueue(e.to); } } _inq[o] = false; } return _dist[_sink] !== _INF; } } exports.Mcmf = Mcmf;