Skip to content

Commit 79aac9b

Browse files
Improve documentation and comments in Dinic algorithm
Updated documentation for Dinic's algorithm, improving clarity and consistency. Adjusted variable names for better readability.
1 parent 746457c commit 79aac9b

File tree

1 file changed

+74
-42
lines changed

1 file changed

+74
-42
lines changed

src/main/java/com/thealgorithms/graph/Dinic.java

Lines changed: 74 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -5,40 +5,54 @@
55
import 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
*/
2330
public 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

Comments
 (0)