55import java .util .Queue ;
66
77/**
8- * Dinic's algorithm for computing maximum flow in a directed graph.
8+ * Implementation of Dinic's Algorithm to compute the maximum flow
9+ * in a directed graph.
910 *
10- * <p>Time complexity: O(E * V^2) in the worst case, but typically faster in practice
11- * and near O(E * sqrt(V)) for unit networks.</p>
11+ * <p><b>Algorithm idea:</b>
12+ * The algorithm works by repeatedly building a level graph using BFS
13+ * and then finding blocking flows using DFS until no more augmenting
14+ * paths exist.</p>
1215 *
13- * <p>The graph is represented using a capacity matrix where capacity[u][v] is the
14- * capacity of the directed edge u -> v. Capacities must be non-negative.
15- * The algorithm builds level graphs using BFS and finds blocking flows using DFS
16- * with current-edge optimization.</p>
16+ * <p><b>Time Complexity:</b>
17+ * Worst case: O(E × V²) <br>
18+ * Practical performance: Much faster, often close to O(E × √V)</p>
1719 *
18- * <p>This implementation mirrors the API and validation style of
20+ * <p>The graph is represented using a capacity matrix where
21+ * {@code capacity[u][v]} denotes the capacity of the directed edge
22+ * from vertex {@code u} to vertex {@code v}.</p>
23+ *
24+ * <p>This implementation follows the same validation style as
1925 * {@link EdmondsKarp#maxFlow(int[][], int, int)} for consistency.</p>
2026 *
21- * @see <a href="https://en.wikipedia.org/wiki/Dinic%27s_algorithm">Wikipedia: Dinic's algorithm</a>
27+ * @see <a href="https://en.wikipedia.org/wiki/Dinic%27s_algorithm">
28+ * Wikipedia: Dinic's Algorithm</a>
2229 */
2330public final class Dinic {
31+
32+ // Private constructor to prevent instantiation
2433 private Dinic () {
2534 }
2635
2736 /**
28- * Computes the maximum flow from source to sink using Dinic's algorithm.
37+ * Computes the maximum flow from a source vertex to a sink vertex
38+ * using Dinic's Algorithm.
2939 *
30- * @param capacity square capacity matrix (n x n); entries must be >= 0
31- * @param source source vertex index in [0, n)
32- * @param sink sink vertex index in [0, n)
33- * @return the maximum flow value
34- * @throws IllegalArgumentException if the input matrix is null/non-square/has negatives or
35- * indices invalid
40+ * @param capacity square matrix representing edge capacities
41+ * @param source index of the source vertex
42+ * @param sink index of the sink vertex
43+ * @return maximum possible flow from source to sink
44+ * @throws IllegalArgumentException if the input matrix is invalid
3645 */
3746 public static int maxFlow (int [][] capacity , int source , int sink ) {
47+
48+ // Validate capacity matrix
3849 if (capacity == null || capacity .length == 0 ) {
3950 throw new IllegalArgumentException ("Capacity matrix must not be null or empty" );
4051 }
52+
4153 final int n = capacity .length ;
54+
55+ // Ensure matrix is square and capacities are non-negative
4256 for (int i = 0 ; i < n ; i ++) {
4357 if (capacity [i ] == null || capacity [i ].length != n ) {
4458 throw new IllegalArgumentException ("Capacity matrix must be square" );
@@ -49,69 +63,87 @@ public static int maxFlow(int[][] capacity, int source, int sink) {
4963 }
5064 }
5165 }
66+
67+ // Validate source and sink
5268 if (source < 0 || sink < 0 || source >= n || sink >= n ) {
5369 throw new IllegalArgumentException ("Source and sink must be valid vertex indices" );
5470 }
71+
5572 if (source == sink ) {
5673 return 0 ;
5774 }
5875
59- // residual capacities
76+ // Create residual graph
6077 int [][] residual = new int [n ][n ];
6178 for (int i = 0 ; i < n ; i ++) {
6279 residual [i ] = Arrays .copyOf (capacity [i ], n );
6380 }
6481
6582 int [] level = new int [n ];
66- int flow = 0 ;
83+ int maxFlow = 0 ;
84+
85+ // Repeatedly build level graph and find blocking flows
6786 while (bfsBuildLevelGraph (residual , source , sink , level )) {
6887 int [] next = new int [n ]; // current-edge optimization
69- int pushed ;
70- do {
71- pushed = dfsBlocking (residual , level , next , source , sink , Integer .MAX_VALUE );
72- flow += pushed ;
73- } while (pushed > 0 );
88+ int flow ;
89+
90+ // Push flow while augmenting paths exist
91+ while ((flow = dfsBlocking (residual , level , next , source , sink , Integer .MAX_VALUE )) > 0 ) {
92+ maxFlow += flow ;
93+ }
7494 }
75- return flow ;
95+ return maxFlow ;
7696 }
7797
98+ /**
99+ * Builds the level graph using BFS.
100+ */
78101 private static boolean bfsBuildLevelGraph (int [][] residual , int source , int sink , int [] level ) {
79102 Arrays .fill (level , -1 );
80103 level [source ] = 0 ;
81- Queue <Integer > q = new ArrayDeque <>();
82- q .add (source );
83- while (!q .isEmpty ()) {
84- int u = q .poll ();
104+
105+ Queue <Integer > queue = new ArrayDeque <>();
106+ queue .add (source );
107+
108+ while (!queue .isEmpty ()) {
109+ int u = queue .poll ();
85110 for (int v = 0 ; v < residual .length ; v ++) {
86111 if (residual [u ][v ] > 0 && level [v ] == -1 ) {
87112 level [v ] = level [u ] + 1 ;
88113 if (v == sink ) {
89114 return true ;
90115 }
91- q .add (v );
116+ queue .add (v );
92117 }
93118 }
94119 }
95120 return level [sink ] != -1 ;
96121 }
97122
98- private static int dfsBlocking (int [][] residual , int [] level , int [] next , int u , int sink , int f ) {
123+ /**
124+ * DFS to find blocking flow in the level graph.
125+ */
126+ private static int dfsBlocking (int [][] residual , int [] level , int [] next ,
127+ int u , int sink , int flow ) {
128+
99129 if (u == sink ) {
100- return f ;
130+ return flow ;
101131 }
132+
102133 final int n = residual .length ;
134+
103135 for (int v = next [u ]; v < n ; v ++, next [u ] = v ) {
104- if (residual [u ][v ] <= 0 ) {
105- continue ;
106- }
107- if ( level [ v ] != level [u ] + 1 ) {
108- continue ;
109- }
110- int pushed = dfsBlocking ( residual , level , next , v , sink , Math . min ( f , residual [ u ][ v ]));
111- if ( pushed > 0 ) {
112- residual [u ][ v ] - = pushed ;
113- residual [ v ][ u ] += pushed ;
114- return pushed ;
136+ if (residual [u ][v ] > 0 && level [ v ] == level [ u ] + 1 ) {
137+ int pushed = dfsBlocking (
138+ residual , level , next , v , sink ,
139+ Math . min ( flow , residual [u ][ v ])
140+ ) ;
141+
142+ if ( pushed > 0 ) {
143+ residual [ u ][ v ] -= pushed ;
144+ residual [v ][ u ] + = pushed ;
145+ return pushed ;
146+ }
115147 }
116148 }
117149 return 0 ;
0 commit comments