Flow
Dinitz
This is based on the implementation on cp-algorithms. But in my opinion this one is much more organized.
Dinitz
// Dinitz {{{
struct Dinitz {
struct Edge {
int v, u, cap, flow=0;
Edge (int v, int u, int cap) : v(v), u(u), cap(cap) {}
};
vector<Edge> edges;
vector<vector<int>> adj;
int n, s, t;
Dinitz(int n, int s, int t) : n(n), s(s), t(t) {
adj.resize(n);
}
void add_edge(int v, int u, int cap) {
edges.emplace_back(v, u, cap);
adj[v].push_back(edges.size()-1);
edges.emplace_back(u, v, 0);
adj[u].push_back(edges.size()-1);
}
vector<int> level;
bool bfs() {
queue<int> Q;
level.assign(n, -1);
level[s] = 0;
Q.push(s);
while (!Q.empty()) {
int v = Q.front(); Q.pop();
for (auto eid : adj[v]) {
auto e = edges[eid];
if (e.cap - e.flow <= 0) continue;
if (level[e.u] != -1) continue;
level[e.u] = level[v] + 1;
Q.push(e.u);
}
}
return level[t] != -1;
}
vector<int> ptr;
int dfs(int v, int f) {
if (f == 0 || v == t) return f;
for (int &cid = ptr[v]; cid < adj[v].size(); cid++) {
int eid = adj[v][cid];
auto &e = edges[eid];
if (e.cap - e.flow <= 0) continue;
if (level[e.u] != level[e.v] + 1) continue;
int newf = dfs(e.u, min(f, e.cap-e.flow));
if (newf == 0) continue;
e.flow += newf;
edges[eid^1].flow -= newf;
return newf;
}
return 0;
}
int flow() {
int f = 0;
while (bfs()) {
ptr.assign(n, 0);
while (int newf = dfs(s, INF))
f += newf;
}
return f;
}
}; //}}}
Dinitz Min-Cost
The same as above, but allows you to set a cost per flow unit for each edge. This is lightly based on the article on cp-algorithms.
It uses SPFA instead of Bellman-Ford since it is usually much faster.
Dinitz Min-Cost
// Dinitz Min Cost {{{
const int INF = 0x3f3f3f3f3f3f3f3f;
struct Dinitz {
struct Edge {
int v, u, cap, flow=0, cost;
Edge(int v, int u, int cap, int cost) : v(v), u(u), cap(cap), cost(cost) {}
};
int n, s, t;
Dinitz(int n, int s, int t) : n(n), s(s), t(t) {
adj.resize(n);
}
vector<Edge> edges;
vector<vector<int>> adj;
void add_edge(int v, int u, int cap, int cost) {
edges.emplace_back(v, u, cap, cost);
adj[v].push_back(size(edges)-1);
edges.emplace_back(u, v, 0, -cost);
adj[u].push_back(size(edges)-1);
}
vector<int> dist;
bool spfa() {
dist.assign(n, INF);
queue<int> Q;
vector<bool> inqueue(n, false);
dist[s] = 0;
Q.push(s);
inqueue[s] = true;
vector<int> cnt(n);
while (!Q.empty()) {
int v = Q.front(); Q.pop();
inqueue[v] = false;
for (auto eid : adj[v]) {
auto const& e = edges[eid];
if (e.cap - e.flow <= 0) continue;
if (dist[e.u] > dist[e.v] + e.cost) {
dist[e.u] = dist[e.v] + e.cost;
if (!inqueue[e.u]) {
Q.push(e.u);
inqueue[e.u] = true;
}
}
}
}
return dist[t] != INF;
}
int cost = 0;
vector<int> ptr;
int dfs(int v, int f) {
if (v == t || f == 0) return f;
for (auto &cid = ptr[v]; cid < size(adj[v]);) {
auto eid = adj[v][cid];
auto &e = edges[eid];
cid++;
if (e.cap - e.flow <= 0) continue;
if (dist[e.v] + e.cost != dist[e.u]) continue;
int newf = dfs(e.u, min(f, e.cap-e.flow));
if (newf == 0) continue;
e.flow += newf;
edges[eid^1].flow -= newf;
cost += e.cost * newf;
return newf;
}
return 0;
}
int total_flow = 0;
int flow() {
while (spfa()) {
ptr.assign(n, 0);
while (int newf = dfs(s, INF))
total_flow += newf;
}
return total_flow;
}
};
//}}}