forked from phpduke/Algorithms-Notebook
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathMinCostMaxFlow.cpp
More file actions
69 lines (69 loc) · 2.54 KB
/
MinCostMaxFlow.cpp
File metadata and controls
69 lines (69 loc) · 2.54 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
/* Min-cost max-flow. cap[i][j] != cap[j][i] is allowed; double edges are not.
* If costs can be negative, call setpi before maxflow, but note that negative cost cycles are not supported.
* To obtain the actual flow, look at positive values only. Time: Approximately O(E^2) */
/*INPUT: - graph, constructed using AddEdge()
// - source
// - sink
// OUTPUT: - (maximum flow value, minimum cost value)
// - To obtain the actual flow, look at positive values only*/
#include <bits/extc++.h> /** keep-include */
const ll INF = numeric_limits<ll>::max() / 4; typedef vector<ll> VL;
struct MCMF {
int N;
vector<vi> ed, red;
vector<VL> cap, flow, cost;
vi seen;
VL dist, pi;
vector<pii> par;
MCMF(int N) :
N(N), ed(N), red(N), cap(N, VL(N)), flow(cap), cost(cap),
seen(N), dist(N), pi(N), par(N) {}
void addEdge(int from, int to, ll cap, ll cost) {
this->cap[from][to] = cap;
this->cost[from][to] = cost;
ed[from].push_back(to);
red[to].push_back(from);
}
void path(int s) {
fill(all(seen), 0);
fill(all(dist), INF);
dist[s] = 0; ll di;
__gnu_pbds::priority_queue<pair<ll, int>> q;
vector<decltype(q)::point_iterator> its(N);
q.push({0, s});
auto relax = [&](int i, ll cap, ll cost, int dir) {
ll val = di - pi[i] + cost;
if (cap && val < dist[i]) {
dist[i] = val;
par[i] = {s, dir};
if (its[i] == q.end()) its[i] = q.push({-dist[i], i});
else q.modify(its[i], {-dist[i], i});
}
};
while (!q.empty()) {
s = q.top().second; q.pop();
seen[s] = 1; di = dist[s] + pi[s];
trav(i, ed[s]) if (!seen[i]) relax(i, cap[s][i] - flow[s][i], cost[s][i], 1);
trav(i, red[s]) if (!seen[i]) relax(i, flow[i][s], -cost[i][s], 0);
}
rep(i,0,N) pi[i] = min(pi[i] + dist[i], INF);
}
pair<ll, ll> maxflow(int s, int t) {
ll totflow = 0, totcost = 0;
while (path(s), seen[t]) {
ll fl = INF;
for (int p,r,x = t; tie(p,r) = par[x], x != s; x = p) fl = min(fl, r ? cap[p][x] - flow[p][x] : flow[x][p]);
totflow += fl;
for (int p,r,x = t; tie(p,r) = par[x], x != s; x = p) if (r) flow[p][x] += fl; else flow[x][p] -= fl;
}
rep(i,0,N) rep(j,0,N) totcost += cost[i][j] * flow[i][j];
return {totflow, totcost};
} // If some costs can be negative, call this[setpi()] before maxflow:
void setpi(int s) { // (otherwise, leave this out)
fill(all(pi), INF); pi[s] = 0;
int it = N, ch = 1; ll v;
while (ch-- && it--) rep(i,0,N) if (pi[i] != INF) trav(to, ed[i]) if (cap[i][to])
if ((v = pi[i] + cost[i][to]) < pi[to]) pi[to] = v, ch = 1;
assert(it >= 0); // negative cost cycle
}
};