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 */
1632public 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