Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
226 changes: 123 additions & 103 deletions ch8/maxflow.java
Original file line number Diff line number Diff line change
@@ -1,55 +1,54 @@
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;
int u, v;
long f;

Edge(int v, long w, long f) {
Edge(int u, int v, long f) {
this.u = u;
this.v = v;
this.w = w;
this.f = f;
}

@Override
public String toString() {
return u + " " + v + " " + 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<>());
}
// Partially adapted from https://github.com/lewin/Algorithms/blob/master/src/Graph/Algorithms/NetworkFlow/Dinic.java
// Contains additional functions from https://github.com/stevenhalim/cpbook-code/blob/master/ch8/maxflow.cpp
class maxflow {
static long INF = 1l << 62; // 4E18

int numVertices, numEdges;
int edgeIndex;
int[] adjNodes, prevEdges, lastEdges, d, last, bfsVertices, bfsEdges;
long[] flows, caps;

maxflow(int numVertices, int numEdges) {
this.numVertices = numVertices;
numEdges *= 2; // * 2 to account for back edges
this.numEdges = numEdges;
this.adjNodes = new int[numEdges];
this.prevEdges = new int[numEdges];
this.lastEdges = new int[numVertices];
this.flows = new long[numEdges];
this.caps = new long[numEdges];
this.edgeIndex = 0;
this.last = new int[numVertices];
Arrays.fill(lastEdges, -1);
}

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

adjNodes[edgeIndex] = v; caps[edgeIndex] = w; flows[edgeIndex] = 0; // u->v, cap w, flow 0
prevEdges[edgeIndex] = lastEdges[u]; lastEdges[u] = edgeIndex++;

adjNodes[edgeIndex] = u; caps[edgeIndex] = directed ? 0 : w; flows[edgeIndex] = 0; // back edge
prevEdges[edgeIndex] = lastEdges[v]; lastEdges[v] = edgeIndex++;
}

long edmondsKarp(int s, int t) {
Expand All @@ -65,7 +64,7 @@ long edmondsKarp(int s, int t) {
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
System.arraycopy(lastEdges, 0, last, 0, numVertices); // important speedup
long f;
while ((f = DFS(s, t, INF)) > 0) { // exhaust blocking flow
mf += f;
Expand All @@ -75,98 +74,119 @@ long dinic(int s, int t) {
}

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 = new int[numVertices];
bfsVertices = new int[numVertices]; // record BFS sp tree
bfsEdges = new int[numVertices];
for (int i = 0; i < numVertices; i++) {
d[i] = -1;
p[i] = new Pair(-1, -1);
bfsVertices[i] = bfsEdges[i] = -1;
}

d[s] = 0;
Queue<Integer> q = new LinkedList<>();
q.offer(s);
while (!q.isEmpty()) {
int u = q.poll();
int[] queue = new int[numVertices];
int front = 0, back = 0;
queue[back++] = s;

while (front < back) {
int u = queue[front++];
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

for (int idx = lastEdges[u]; idx != -1; idx = prevEdges[idx]) { // explore neighbors of u
int v = adjNodes[idx]; // stored in adjNodes[idx]

if (d[v] == -1 & flows[idx] < caps[idx]) {
d[v] = d[u] + 1;
q.offer(v);
p[v] = new Pair(u, idx);
queue[back++] = v;
bfsVertices[v] = u;
bfsEdges[v] = 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
long sendOneFlow(int s, int t, long f) { // send one flow from s->t
if (s == t) return f; // bottleneck edge f found

int u = bfsVertices[t];
int idx = bfsEdges[t];

long pushed = sendOneFlow(s, u, Math.min(f, caps[idx] - flows[idx]));
flows[idx] += pushed;
flows[idx ^ 1] -= pushed; // back flow
return pushed;
}

long DFS(int u, int t, long f) { // traverse from u->t
if ((u == t) || (f == 0)) return f;

for (int idx = last[u]; idx != -1; last[u] = idx = prevEdges[idx]) { // from last edge
int v = adjNodes[idx];
if (d[v] != d[u] + 1) continue; // not part of layer graph

long pushed = DFS(v, t, Math.min(f, caps[idx] - flows[idx]));

if (pushed > 0) {
flows[idx] += pushed;
flows[idx ^ 1] -= pushed; // back flow
return pushed;
}
}

return 0;
}

// Run after performing Dinics/Edmonds Karp to get
// nodes in min cut
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 = new int[numVertices];
bfsVertices = new int[numVertices]; // record BFS sp tree
bfsEdges = new int[numVertices];
for (int i = 0; i < numVertices; i++) {
d[i] = -1;
p[i] = new Pair(-1, -1);
bfsVertices[i] = bfsEdges[i] = -1;
}

d[s] = 0;
Queue<Integer> q = new LinkedList<>();
q.offer(s);
int[] queue = new int[numVertices];
int front = 0, back = 0;
queue[back++] = s;
result.add(s);
while (!q.isEmpty()) {
int u = q.poll();

while (front < back) {
int u = queue[front++];
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

for (int idx = lastEdges[u]; idx != -1; idx = prevEdges[idx]) { // explore neighbors of u
int v = adjNodes[idx]; // stored in adjNodes[idx]

if (d[v] == -1 & flows[idx] < caps[idx]) {
d[v] = d[u] + 1;
q.offer(v);
p[v] = new Pair(u, idx);
queue[back++] = v;
bfsVertices[v] = u;
bfsEdges[v] = 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;
return result;
}

// Run after performing Dinics/Edmonds Karp to get
// edges in flow graph
List<Edge> getFlowGraphEdges() {
List<Edge> result = new ArrayList<>();

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;
for (int i = 0; i < numEdges; i++) {
if (flows[i] > 0) {
result.add(new Edge(adjNodes[i ^ 1], adjNodes[i], flows[i]));
}
}
return 0;

return result;
}
}

Loading