Skip to content

Commit 8de04c1

Browse files
williamfisetclaude
andauthored
Refactor FordFulkersonDfsSolverAdjacencyList: add docs, clean up code (williamfiset#1293)
Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 6e239c9 commit 8de04c1

File tree

1 file changed

+88
-90
lines changed

1 file changed

+88
-90
lines changed
Lines changed: 88 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,25 @@
11
/**
2-
* An implementation of the Ford-Fulkerson (FF) method with a DFS as a method of finding augmenting
3-
* paths. FF allows you to find the max flow through a directed graph and the min cut as a
4-
* byproduct.
2+
* Ford-Fulkerson Max Flow — DFS Augmenting Paths (Adjacency List)
53
*
6-
* <p>Time Complexity: O(fE), where f is the max flow and E is the number of edges
4+
* <p>The Ford-Fulkerson method finds the maximum flow in a flow network by
5+
* repeatedly finding augmenting paths from source to sink and pushing flow
6+
* along them. This implementation uses DFS to find each augmenting path.
7+
*
8+
* <p>Algorithm:
9+
* <ol>
10+
* <li>Run DFS from source to find a path to the sink with available capacity.</li>
11+
* <li>Compute the bottleneck (minimum residual capacity along the path).</li>
12+
* <li>Augment flow along the path by the bottleneck value.</li>
13+
* <li>Repeat until no augmenting path exists.</li>
14+
* </ol>
15+
*
16+
* <p>The min-cut is obtained as a byproduct: after the algorithm terminates,
17+
* all nodes still reachable from the source in the residual graph belong to
18+
* the source side of the minimum cut.
19+
*
20+
* <p>Time Complexity: O(fE), where f is the max flow and E is the number of edges.
21+
* The DFS-based approach can be slow on graphs with large integer capacities
22+
* because each augmenting path may only push one unit of flow.
723
*
824
* @author William Fiset, william.alexandre.fiset@gmail.com
925
*/
@@ -16,8 +32,8 @@
1632
public class FordFulkersonDfsSolverAdjacencyList extends NetworkFlowSolverBase {
1733

1834
/**
19-
* Creates an instance of a flow network solver. Use the {@link #addEdge(int, int, int)} method to
20-
* add edges to the graph.
35+
* Creates an instance of a flow network solver. Use the {@link #addEdge} method to add edges to
36+
* the graph.
2137
*
2238
* @param n - The number of nodes in the graph including source and sink nodes.
2339
* @param s - The index of the source node, 0 <= s < n
@@ -27,34 +43,33 @@ public FordFulkersonDfsSolverAdjacencyList(int n, int s, int t) {
2743
super(n, s, t);
2844
}
2945

30-
// Performs the Ford-Fulkerson method applying a depth first search as
31-
// a means of finding an augmenting path.
3246
@Override
3347
public void solve() {
34-
35-
// Find max flow by adding all augmenting path flows.
48+
// Repeatedly find augmenting paths via DFS and accumulate flow.
3649
for (long f = dfs(s, INF); f != 0; f = dfs(s, INF)) {
3750
markAllNodesAsUnvisited();
3851
maxFlow += f;
3952
}
4053

41-
// Find min cut.
42-
for (int i = 0; i < n; i++) if (visited(i)) minCut[i] = true;
54+
// Nodes still reachable from source in the residual graph form the min-cut.
55+
for (int i = 0; i < n; i++) {
56+
if (visited(i)) {
57+
minCut[i] = true;
58+
}
59+
}
4360
}
4461

4562
private long dfs(int node, long flow) {
46-
// At sink node, return augmented path flow.
47-
if (node == t) return flow;
63+
if (node == t) {
64+
return flow;
65+
}
4866

49-
List<Edge> edges = graph[node];
5067
visit(node);
5168

52-
for (Edge edge : edges) {
69+
for (Edge edge : graph[node]) {
5370
long rcap = edge.remainingCapacity();
5471
if (rcap > 0 && !visited(edge.to)) {
5572
long bottleNeck = dfs(edge.to, min(flow, rcap));
56-
57-
// Augment flow with bottle neck value
5873
if (bottleNeck > 0) {
5974
edge.augment(bottleNeck);
6075
return bottleNeck;
@@ -64,21 +79,69 @@ private long dfs(int node, long flow) {
6479
return 0;
6580
}
6681

67-
/* Example */
82+
// ==================== Main ====================
6883

6984
public static void main(String[] args) {
70-
// exampleFromSlides();
71-
// testSmallFlowGraph();
72-
exampleFromSlides2();
85+
testSmallFlowGraph();
86+
testExampleFromSlides();
87+
testLargerFlowGraph();
88+
}
89+
90+
// Testing graph from:
91+
// http://crypto.cs.mcgill.ca/~crepeau/COMP251/KeyNoteSlides/07demo-maxflowCS-C.pdf
92+
private static void testSmallFlowGraph() {
93+
int n = 6;
94+
int s = n - 1;
95+
int t = n - 2;
96+
97+
FordFulkersonDfsSolverAdjacencyList solver =
98+
new FordFulkersonDfsSolverAdjacencyList(n, s, t);
99+
100+
// Source edges
101+
solver.addEdge(s, 0, 10);
102+
solver.addEdge(s, 1, 10);
103+
104+
// Sink edges
105+
solver.addEdge(2, t, 10);
106+
solver.addEdge(3, t, 10);
107+
108+
// Middle edges
109+
solver.addEdge(0, 1, 2);
110+
solver.addEdge(0, 2, 4);
111+
solver.addEdge(0, 3, 8);
112+
solver.addEdge(1, 3, 9);
113+
solver.addEdge(3, 2, 6);
114+
115+
System.out.println(solver.getMaxFlow()); // 19
116+
}
117+
118+
private static void testExampleFromSlides() {
119+
int n = 6;
120+
int s = n - 2;
121+
int t = n - 1;
122+
123+
FordFulkersonDfsSolverAdjacencyList solver =
124+
new FordFulkersonDfsSolverAdjacencyList(n, s, t);
125+
126+
solver.addEdge(s, 1, 10);
127+
solver.addEdge(1, 3, 15);
128+
solver.addEdge(3, 0, 6);
129+
solver.addEdge(0, 2, 25);
130+
solver.addEdge(2, t, 10);
131+
132+
solver.addEdge(s, 0, 10);
133+
solver.addEdge(3, t, 10);
134+
135+
System.out.println(solver.getMaxFlow()); // 20
73136
}
74137

75-
private static void exampleFromSlides2() {
138+
private static void testLargerFlowGraph() {
76139
int n = 12;
77140
int s = n - 2;
78141
int t = n - 1;
79142

80-
FordFulkersonDfsSolverAdjacencyList solver;
81-
solver = new FordFulkersonDfsSolverAdjacencyList(n, s, t);
143+
FordFulkersonDfsSolverAdjacencyList solver =
144+
new FordFulkersonDfsSolverAdjacencyList(n, s, t);
82145

83146
solver.addEdge(s, 1, 2);
84147
solver.addEdge(s, 2, 1);
@@ -106,70 +169,5 @@ private static void exampleFromSlides2() {
106169
solver.addEdge(8, t, 4);
107170

108171
System.out.println(solver.getMaxFlow());
109-
110-
List<Edge>[] g = solver.getGraph();
111-
for (List<Edge> edges : g) {
112-
for (Edge e : edges) {
113-
if (e.to == s || e.from == t) continue;
114-
if (e.from == s || e.to == t || e.from < e.to) System.out.println(e.toString(s, t));
115-
// System.out.println(e.residual.toString(s, t));
116-
}
117-
}
118-
}
119-
120-
private static void exampleFromSlides() {
121-
int n = 6;
122-
int s = n - 2;
123-
int t = n - 1;
124-
125-
FordFulkersonDfsSolverAdjacencyList solver;
126-
solver = new FordFulkersonDfsSolverAdjacencyList(n, s, t);
127-
128-
solver.addEdge(s, 1, 10);
129-
solver.addEdge(1, 3, 15);
130-
solver.addEdge(3, 0, 6);
131-
solver.addEdge(0, 2, 25);
132-
solver.addEdge(2, t, 10);
133-
134-
solver.addEdge(s, 0, 10);
135-
solver.addEdge(3, t, 10);
136-
137-
System.out.println(solver.getMaxFlow());
138-
139-
List<Edge>[] g = solver.getGraph();
140-
for (List<Edge> edges : g) {
141-
for (Edge e : edges) {
142-
System.out.println(e.toString(s, t));
143-
// System.out.println(e.residual.toString(s, t));
144-
}
145-
}
146-
}
147-
148-
// Testing graph from:
149-
// http://crypto.cs.mcgill.ca/~crepeau/COMP251/KeyNoteSlides/07demo-maxflowCS-C.pdf
150-
private static void testSmallFlowGraph() {
151-
int n = 6;
152-
int s = n - 1;
153-
int t = n - 2;
154-
155-
FordFulkersonDfsSolverAdjacencyList solver;
156-
solver = new FordFulkersonDfsSolverAdjacencyList(n, s, t);
157-
158-
// Source edges
159-
solver.addEdge(s, 0, 10);
160-
solver.addEdge(s, 1, 10);
161-
162-
// Sink edges
163-
solver.addEdge(2, t, 10);
164-
solver.addEdge(3, t, 10);
165-
166-
// Middle edges
167-
solver.addEdge(0, 1, 2);
168-
solver.addEdge(0, 2, 4);
169-
solver.addEdge(0, 3, 8);
170-
solver.addEdge(1, 3, 9);
171-
solver.addEdge(3, 2, 6);
172-
173-
System.out.println(solver.getMaxFlow()); // 19
174172
}
175173
}

0 commit comments

Comments
 (0)