-
Notifications
You must be signed in to change notification settings - Fork 110
/
Copy pathMax Flow Goldberg Tarjan.cpp
121 lines (111 loc) · 2.7 KB
/
Max Flow Goldberg Tarjan.cpp
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
//
// Maximum Flow (Goldberg-Tarjan, aka. Push-Relabel, Preflow-Push)
//
// Description:
// Given a directed network G = (V, E) with edge capacity c: E->R.
// The algorithm finds a maximum flow.
//
// Algorithm:
// Goldberg-Tarjan's push-relabel algorithm with gap-heuristics.
//
// Complexity:
// O(n^3)
//
// Verified:
// SPOJ FASTFLOW
//
// Reference:
// B. H. Korte and Jens Vygen (2008):
// Combinatorial Optimization: Theory and Algorithms.
// Springer Berlin Heidelberg.
//
#include <iostream>
#include <vector>
#include <cstdio>
#include <queue>
#include <algorithm>
#include <functional>
using namespace std;
#define fst first
#define snd second
#define all(c) ((c).begin()), ((c).end())
const long long INF = (1ll << 50);
struct graph {
typedef long long flow_type;
struct edge {
int src, dst;
flow_type capacity, flow;
size_t rev;
};
int n;
vector<vector<edge>> adj;
graph(int n) : n(n), adj(n) { }
void add_edge(int src, int dst, int capacity) {
adj[src].push_back({src, dst, capacity, 0, adj[dst].size()});
adj[dst].push_back({dst, src, 0, 0, adj[src].size() - 1});
}
flow_type max_flow(int s, int t) {
vector<flow_type> excess(n);
vector<int> dist(n), active(n), count(2 * n);
queue<int> Q;
auto enqueue = [&](int v) {
if (!active[v] && excess[v] > 0) { active[v] = true; Q.push(v); }
};
auto push = [&](edge & e) {
flow_type f = min(excess[e.src], e.capacity - e.flow);
if (dist[e.src] <= dist[e.dst] || f == 0) return;
e.flow += f;
adj[e.dst][e.rev].flow -= f;
excess[e.dst] += f;
excess[e.src] -= f;
enqueue(e.dst);
};
dist[s] = n; active[s] = active[t] = true;
count[0] = n - 1; count[n] = 1;
for (int u = 0; u < n; ++u)
for (auto &e : adj[u]) e.flow = 0;
for (auto &e : adj[s]) {
excess[s] += e.capacity;
push(e);
}
while (!Q.empty()) {
int u = Q.front(); Q.pop();
active[u] = false;
for (auto &e : adj[u]) push(e);
if (excess[u] > 0) {
if (count[dist[u]] == 1) {
int k = dist[u]; // Gap Heuristics
for (int v = 0; v < n; v++) {
if (dist[v] < k) continue;
count[dist[v]]--;
dist[v] = max(dist[v], n + 1);
count[dist[v]]++;
enqueue(v);
}
} else {
count[dist[u]]--; // Relabel
dist[u] = 2 * n;
for (auto &e : adj[u])
if (e.capacity > e.flow)
dist[u] = min(dist[u], dist[e.dst] + 1);
count[dist[u]]++;
enqueue(u);
}
}
}
flow_type flow = 0;
for (auto e : adj[s]) flow += e.flow;
return flow;
}
};
int main() {
for (int n, m; scanf("%d %d", &n, &m) == 2; ) {
graph g(n);
for (int i = 0; i < m; ++i) {
int u, v, w;
scanf("%d %d %d", &u, &v, &w);
g.add_edge(u, v, w);
}
printf("%d\n", g.max_flow(0, n - 1));
}
}