Skip to content

Commit 1221e52

Browse files
authored
FordFulkerson
1 parent d86413f commit 1221e52

File tree

1 file changed

+124
-0
lines changed

1 file changed

+124
-0
lines changed
Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,124 @@
1+
package com.thealgorithms.datastructures.graphs;
2+
3+
import java.util.ArrayList;
4+
import java.util.Collections;
5+
import java.util.Comparator;
6+
import java.util.List;
7+
import java.util.concurrent.atomic.AtomicInteger;
8+
import java.util.stream.IntStream;
9+
10+
11+
12+
@Data
13+
public class FordFulkerson<T> {
14+
15+
// List to store all the paths found from source to destination
16+
private final List<List<Vertex<T>>> paths = new ArrayList<>();
17+
18+
/**
19+
* Runs the Ford-Fulkerson algorithm to calculate the maximum flow from the source to the destination.
20+
*
21+
* @param source The source vertex.
22+
* @param destination The destination vertex.
23+
* @return The maximum possible flow in the network.
24+
*/
25+
public int run(Vertex<T> source, Vertex<T> destination) {
26+
// Find all possible paths from source to destination
27+
findAllPaths(source, destination, new ArrayList<>(Collections.singleton(source)));
28+
29+
// Atomic integer to hold the maximum flow value
30+
AtomicInteger maxFlow = new AtomicInteger();
31+
32+
// Iterate over each path, sorted by the minimum flow in descending order
33+
paths.stream()
34+
.sorted(Comparator.comparingInt(this::getMinFlowInPath).reversed())
35+
.forEach(path -> {
36+
// Get the minimum flow (bottleneck) in the current path
37+
Integer minimum = getMinFlowInPath(path);
38+
39+
// Subtract the minimum flow from all edges in the path
40+
IntStream.range(0, path.size() - 1)
41+
.forEach(vertexIdx -> removeMinFlowFromVerticesInPath(path, minimum, vertexIdx));
42+
43+
// Add the minimum flow to the total max flow
44+
maxFlow.addAndGet(minimum);
45+
});
46+
47+
// Return the calculated maximum flow
48+
return maxFlow.get();
49+
}
50+
51+
/**
52+
* Finds the minimum flow in a given path.
53+
*
54+
* @param path The path in which to find the minimum flow.
55+
* @return The minimum flow in the path.
56+
*/
57+
private Integer getMinFlowInPath(List<Vertex<T>> path) {
58+
return IntStream.range(0, path.size() - 1)
59+
.mapToObj(vertexIdx -> getNeighborEdgeWeight(path, vertexIdx))
60+
.min(Integer::compareTo).orElse(0);
61+
}
62+
63+
/**
64+
* Reduces the flow of each edge in the path by the minimum flow value.
65+
*
66+
* @param path The path where the flow should be reduced.
67+
* @param min The minimum flow value to subtract.
68+
* @param vertexIdx The index of the current vertex in the path.
69+
*/
70+
private void removeMinFlowFromVerticesInPath(List<Vertex<T>> path, Integer min, int vertexIdx) {
71+
// Update the edge's flow by subtracting the minimum flow
72+
path.get(vertexIdx).getNeighbors().put(
73+
path.get(vertexIdx + 1),
74+
getNeighborEdgeWeight(path, vertexIdx) - min
75+
);
76+
}
77+
78+
/**
79+
* Gets the weight of the edge between two adjacent vertices in a path.
80+
*
81+
* @param path The path containing the vertices.
82+
* @param vertexIdx The index of the current vertex in the path.
83+
* @return The weight of the edge between the current vertex and the next vertex in the path.
84+
*/
85+
private Integer getNeighborEdgeWeight(List<Vertex<T>> path, int vertexIdx) {
86+
return path.get(vertexIdx).getNeighbors().get(path.get(vertexIdx + 1));
87+
}
88+
89+
/**
90+
* Recursively finds all paths from the current vertex to the destination vertex.
91+
*
92+
* @param current The current vertex being explored.
93+
* @param destination The destination vertex.
94+
* @param currentPath The current path being built.
95+
*/
96+
private void findAllPaths(Vertex<T> current, Vertex<T> destination, List<Vertex<T>> currentPath) {
97+
// If the current vertex is the destination, add the current path to the list of paths
98+
if (current.equals(destination)) {
99+
paths.add(new ArrayList<>(currentPath));
100+
return;
101+
}
102+
103+
// Mark the current vertex as visited to avoid revisiting
104+
current.setVisited(true);
105+
106+
// Explore all unvisited neighbors of the current vertex
107+
current.getNeighbors().keySet().stream()
108+
.filter(neighbor -> !neighbor.isVisited())
109+
.forEach(neighbor -> {
110+
// Add the neighbor to the current path
111+
currentPath.add(neighbor);
112+
113+
// Recursively find paths from the neighbor to the destination
114+
findAllPaths(neighbor, destination, currentPath);
115+
116+
// Backtrack by removing the neighbor from the current path
117+
currentPath.remove(neighbor);
118+
});
119+
120+
// Mark the current vertex as unvisited to allow for other paths
121+
current.setVisited(false);
122+
}
123+
}
124+

0 commit comments

Comments
 (0)