forked from stevenhalim/cpbook-code
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmaxflow.java
172 lines (157 loc) · 5.44 KB
/
maxflow.java
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
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
import java.io.*;
import java.util.*;
// (Nearly) 1-1 translation of maxflow.cpp with min-cut augmentation
class Pair {
int first, second;
Pair(int first, int second) {
this.first = first;
this.second = second;
}
}
class Edge {
int v;
long w, f;
Edge(int v, long w, long f) {
this.v = v;
this.w = w;
this.f = f;
}
}
public class maxflow {
static long INF = 1000000000000000000l;
int V;
Edge[] EL;
int ELSize;
List<List<Integer>> AL;
int[] d, last;
Pair[] p;
maxflow(int initialV, int numEdges) {
V = initialV;
EL = new Edge[2 * numEdges]; // 2 * to account for back edges
ELSize = 0;
AL = new ArrayList<>();
for (int i = 0; i < V; i++) {
AL.add(new ArrayList<>());
}
}
void addEdge(int u, int v, long w, boolean directed) {
if (u == v) return; // safeguard: no self loop
EL[ELSize] = new Edge(v, w, 0); // u->v, cap w, flow 0
ELSize++;
AL.get(u).add(ELSize - 1); // remember this index
EL[ELSize] = new Edge(u, directed ? 0 : w, 0); // back edge
ELSize++;
AL.get(v).add(ELSize - 1); // remember this index
}
long edmondsKarp(int s, int t) {
long mf = 0; // mf stands for max_flow
while (BFS(s, t)) { // an O(V*E^2) algorithm
long f = sendOneFlow(s, t, INF); // find and send 1 flow f
if (f == 0) break; // if f == 0, stop
mf += f; // if f > 0, add to mf
}
return mf;
}
long dinic(int s, int t) {
long mf = 0; // mf stands for max_flow
while (BFS(s, t)) { // an O(V^2*E) algorithm
last = new int[V]; // important speedup
long f;
while ((f = DFS(s, t, INF)) > 0) { // exhaust blocking flow
mf += f;
}
}
return mf;
}
boolean BFS(int s, int t) { // find augmenting path
d = new int[V];
p = new Pair[V]; // record BFS sp tree
for (int i = 0; i < V; i++) {
d[i] = -1;
p[i] = new Pair(-1, -1);
}
d[s] = 0;
Queue<Integer> q = new LinkedList<>();
q.offer(s);
while (!q.isEmpty()) {
int u = q.poll();
if (u == t) break; // stop as sink t reached
for (int idx : AL.get(u)) { // explore neighbors of u
Edge e = EL[idx]; // stored in EL[idx]
int v = e.v;
long cap = e.w;
long flow = e.f;
if ((cap - flow > 0) && (d[v] == -1)) { // positive residual edge
d[v] = d[u] + 1;
q.offer(v);
p[v] = new Pair(u, idx);
}
}
}
return d[t] != -1;
}
// Run after performing Dinics/Edmonds Karp to get nodes in min-cut
// Basically performs BFS on the flow graph one more time
List<Integer> minCut(int s, int t) {
List<Integer> result = new ArrayList<>();
d = new int[V];
p = new Pair[V]; // record BFS sp tree
for (int i = 0; i < V; i++) {
d[i] = -1;
p[i] = new Pair(-1, -1);
}
d[s] = 0;
Queue<Integer> q = new LinkedList<>();
q.offer(s);
result.add(s);
while (!q.isEmpty()) {
int u = q.poll();
if (u == t) break; // stop as sink t reached
for (int idx : AL.get(u)) { // explore neighbors of u
Edge e = EL[idx]; // stored in EL[idx]
int v = e.v;
long cap = e.w;
long flow = e.f;
if ((cap - flow > 0) && (d[v] == -1)) { // positive residual edge
d[v] = d[u] + 1;
q.offer(v);
p[v] = new Pair(u, idx);
result.add(v);
}
}
}
return result;
}
long sendOneFlow(int s, int t, long f) { // send one flow from s->t
if (s == t) return f; // bottleneck edge f found
Pair pair = p[t];
int u = pair.first;
int idx = pair.second;
Edge e = EL[idx];
long cap = e.w;
long flow = e.f;
long pushed = sendOneFlow(s, u, Math.min(f, cap - flow));
e.f += pushed;
EL[idx ^ 1].f -= pushed; // back flow
return pushed;
}
long DFS(int u, int t, long f) { // traverse from s->t
if ((u == t) || (f == 0)) return f;
int start = last[u];
int stop = AL.get(u).size();
for (int i = start; i < stop; i++) { // from last edge
Edge e = EL[AL.get(u).get(i)];
int v = e.v;
long cap = e.w;
long flow = e.f;
if (d[v] != d[u] + 1) continue; // not part of layer graph
long pushed;
if ((pushed = DFS(v, t, Math.min(f, cap - flow))) > 0) {
e.f += pushed;
EL[AL.get(u).get(i) ^ 1].f -= pushed; // back flow
return pushed;
}
}
return 0;
}
}