-
Notifications
You must be signed in to change notification settings - Fork 540
Expand file tree
/
Copy pathmaxflow.cpp
More file actions
131 lines (115 loc) · 4.23 KB
/
maxflow.cpp
File metadata and controls
131 lines (115 loc) · 4.23 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
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
// Disclaimer: This code is a hybrid between old CP1-2-3 implementation of
// Edmonds Karp's algorithm -- re-written in OOP fashion and the fast
// Dinic's algorithm implementation by
// https://github.com/jaehyunp/stanfordacm/blob/master/code/Dinic.cc
// This code is written in modern C++17 standard
#include <bits/stdc++.h>
using namespace std;
typedef long long ll;
typedef tuple<int, ll, ll> edge;
typedef vector<int> vi;
typedef pair<int, int> ii;
const ll INF = 1e18; // large enough
class max_flow {
private:
int V;
vector<edge> EL;
vector<vi> AL;
vi d, last;
vector<ii> p;
bool BFS(int s, int t) { // find augmenting path
d.assign(V, -1); d[s] = 0;
queue<int> q({s});
p.assign(V, {-1, -1}); // record BFS sp tree
while (!q.empty()) {
int u = q.front(); q.pop();
if (u == t) break; // stop as sink t reached
for (auto &idx : AL[u]) { // explore neighbors of u
auto &[v, cap, flow] = EL[idx]; // stored in EL[idx]
if ((cap-flow > 0) && (d[v] == -1)) // positive residual edge
d[v] = d[u]+1, q.push(v), p[v] = {u, idx}; // 3 lines in one!
}
}
return d[t] != -1; // has an augmenting path
}
ll send_one_flow(int s, int t, ll f = INF) { // send one flow from s->t
if (s == t) return f; // bottleneck edge f found
auto &[u, idx] = p[t];
auto &cap = get<1>(EL[idx]), &flow = get<2>(EL[idx]);
ll pushed = send_one_flow(s, u, min(f, cap-flow));
flow += pushed;
auto &rflow = get<2>(EL[idx^1]); // back edge
rflow -= pushed; // back flow
return pushed;
}
ll DFS(int u, int t, ll f = INF) { // traverse from s->t
if ((u == t) || (f == 0)) return f;
for (int &i = last[u]; i < (int)AL[u].size(); ++i) { // from last edge
auto &[v, cap, flow] = EL[AL[u][i]];
if (d[v] != d[u]+1) continue; // not part of layer graph
if (ll pushed = DFS(v, t, min(f, cap-flow))) {
flow += pushed;
auto &rflow = get<2>(EL[AL[u][i]^1]); // back edge
rflow -= pushed;
return pushed;
}
}
return 0;
}
public:
max_flow(int initialV) : V(initialV) {
EL.clear();
AL.assign(V, vi());
}
// if you are adding a bidirectional edge u<->v with weight w into your
// flow graph, set directed = false (default value is directed = true)
void add_edge(int u, int v, ll w, bool directed = true) {
if (u == v) return; // safeguard: no self loop
EL.emplace_back(v, w, 0); // u->v, cap w, flow 0
AL[u].push_back(EL.size()-1); // remember this index
EL.emplace_back(u, directed ? 0 : w, 0); // back edge
AL[v].push_back(EL.size()-1); // remember this index
}
ll edmonds_karp(int s, int t) {
ll mf = 0; // mf stands for max_flow
while (BFS(s, t)) { // an O(V*E^2) algorithm
ll f = send_one_flow(s, t); // find and send 1 flow f
if (f == 0) break; // if f == 0, stop
mf += f; // if f > 0, add to mf
}
return mf;
}
ll dinic(int s, int t) {
ll mf = 0; // mf stands for max_flow
while (BFS(s, t)) { // an O(V^2*E) algorithm
last.assign(V, 0); // important speedup
while (ll f = DFS(s, t)) // exhaust blocking flow
mf += f;
}
return mf;
}
};
int main() {
/*
// Graph in Figure 8.11
4 0 3
2 1 8 2 8
2 2 1 3 8
1 3 8
0
// the max flow value of that graph should be 16
*/
freopen("maxflow_in.txt", "r", stdin);
int V, s, t; scanf("%d %d %d", &V, &s, &t);
max_flow mf(V);
for (int u = 0; u < V; ++u) {
int k; scanf("%d", &k);
while (k--) {
int v, w; scanf("%d %d", &v, &w);
mf.add_edge(u, v, w); // default: directed edge
}
}
// printf("%lld\n", mf.edmonds_karp(s, t));
printf("%lld\n", mf.dinic(s, t));
return 0;
}