diff --git a/src/main/java/com/thealgorithms/dynamicprogramming/FordFulkerson.java b/src/main/java/com/thealgorithms/dynamicprogramming/FordFulkerson.java index 6168ec6e..76995f1c 100644 --- a/src/main/java/com/thealgorithms/dynamicprogramming/FordFulkerson.java +++ b/src/main/java/com/thealgorithms/dynamicprogramming/FordFulkerson.java @@ -2,76 +2,54 @@ package com.thealgorithms.dynamicprogramming; import java.util.LinkedList; import java.util.Queue; -import java.util.Vector; public final class FordFulkerson { + private static final int INF = Integer.MAX_VALUE; + private FordFulkerson() { } - static final int INF = 987654321; - // edges - static int vertexCount; - static int[][] capacity; - static int[][] flow; - - public static void main(String[] args) { - System.out.println("Vertex Count : 6"); - vertexCount = 6; - capacity = new int[vertexCount][vertexCount]; - - capacity[0][1] = 12; - capacity[0][3] = 13; - capacity[1][2] = 10; - capacity[2][3] = 13; - capacity[2][4] = 3; - capacity[2][5] = 15; - capacity[3][2] = 7; - capacity[3][4] = 15; - capacity[4][5] = 17; - - System.out.println("Max capacity in networkFlow : " + networkFlow(0, 5)); - } - - private static int networkFlow(int source, int sink) { - flow = new int[vertexCount][vertexCount]; + public static int networkFlow(int vertexCount, int[][] capacity, int[][] flow, int source, int sink) { int totalFlow = 0; + while (true) { - Vector parent = new Vector<>(vertexCount); - for (int i = 0; i < vertexCount; i++) { - parent.add(-1); - } - Queue q = new LinkedList<>(); - parent.set(source, source); - q.add(source); - while (!q.isEmpty() && parent.get(sink) == -1) { - int here = q.peek(); - q.poll(); - for (int there = 0; there < vertexCount; ++there) { - if (capacity[here][there] - flow[here][there] > 0 && parent.get(there) == -1) { - q.add(there); - parent.set(there, here); + int[] parent = new int[vertexCount]; + boolean[] visited = new boolean[vertexCount]; + Queue queue = new LinkedList<>(); + + queue.add(source); + visited[source] = true; + parent[source] = -1; + + while (!queue.isEmpty() && !visited[sink]) { + int current = queue.poll(); + + for (int next = 0; next < vertexCount; next++) { + if (!visited[next] && capacity[current][next] - flow[current][next] > 0) { + queue.add(next); + visited[next] = true; + parent[next] = current; } } } - if (parent.get(sink) == -1) { - break; + + if (!visited[sink]) { + break; // No more augmenting paths } - int amount = INF; - String printer = "path : "; - StringBuilder sb = new StringBuilder(); - for (int p = sink; p != source; p = parent.get(p)) { - amount = Math.min(capacity[parent.get(p)][p] - flow[parent.get(p)][p], amount); - sb.append(p + "-"); + int pathFlow = INF; + for (int v = sink; v != source; v = parent[v]) { + int u = parent[v]; + pathFlow = Math.min(pathFlow, capacity[u][v] - flow[u][v]); } - sb.append(source); - for (int p = sink; p != source; p = parent.get(p)) { - flow[parent.get(p)][p] += amount; - flow[p][parent.get(p)] -= amount; + + for (int v = sink; v != source; v = parent[v]) { + int u = parent[v]; + flow[u][v] += pathFlow; + flow[v][u] -= pathFlow; } - totalFlow += amount; - printer += sb.reverse() + " / max flow : " + totalFlow; - System.out.println(printer); + + totalFlow += pathFlow; } return totalFlow; diff --git a/src/test/java/com/thealgorithms/dynamicprogramming/FordFulkersonTest.java b/src/test/java/com/thealgorithms/dynamicprogramming/FordFulkersonTest.java new file mode 100644 index 00000000..d4d38ed5 --- /dev/null +++ b/src/test/java/com/thealgorithms/dynamicprogramming/FordFulkersonTest.java @@ -0,0 +1,94 @@ +package com.thealgorithms.dynamicprogramming; + +import static org.junit.jupiter.api.Assertions.assertEquals; + +import org.junit.jupiter.api.Test; + +public class FordFulkersonTest { + @Test + public void testMaxFlow() { + int vertexCount = 6; + int[][] capacity = new int[vertexCount][vertexCount]; + int[][] flow = new int[vertexCount][vertexCount]; + + // Setting up the capacity graph + capacity[0][1] = 12; + capacity[0][3] = 13; + capacity[1][2] = 10; + capacity[2][3] = 13; + capacity[2][4] = 3; + capacity[2][5] = 15; + capacity[3][2] = 7; + capacity[3][4] = 15; + capacity[4][5] = 17; + + int maxFlow = FordFulkerson.networkFlow(vertexCount, capacity, flow, 0, 5); + assertEquals(23, maxFlow); + } + + @Test + public void testNoFlow() { + int vertexCount = 6; + int[][] capacity = new int[vertexCount][vertexCount]; + int[][] flow = new int[vertexCount][vertexCount]; + + // No connections between source and sink + capacity[0][1] = 10; + capacity[2][3] = 10; + + int maxFlow = FordFulkerson.networkFlow(vertexCount, capacity, flow, 1, 4); + assertEquals(0, maxFlow); + } + + @Test + public void testSinglePath() { + int vertexCount = 6; + int[][] capacity = new int[vertexCount][vertexCount]; + int[][] flow = new int[vertexCount][vertexCount]; + + // Setting up a single path from source to sink + capacity[0][1] = 5; + capacity[1][2] = 5; + capacity[2][3] = 5; + capacity[3][4] = 5; + capacity[4][5] = 5; + + int maxFlow = FordFulkerson.networkFlow(vertexCount, capacity, flow, 0, 5); + assertEquals(5, maxFlow); + } + + @Test + public void testParallelPaths() { + int vertexCount = 4; + int[][] capacity = new int[vertexCount][vertexCount]; + int[][] flow = new int[vertexCount][vertexCount]; + + // Setting up parallel paths from source to sink + capacity[0][1] = 10; + capacity[0][2] = 10; + capacity[1][3] = 10; + capacity[2][3] = 10; + + int maxFlow = FordFulkerson.networkFlow(vertexCount, capacity, flow, 0, 3); + assertEquals(20, maxFlow); + } + + @Test + public void testComplexNetwork() { + int vertexCount = 5; + int[][] capacity = new int[vertexCount][vertexCount]; + int[][] flow = new int[vertexCount][vertexCount]; + + // Complex network + capacity[0][1] = 10; + capacity[0][2] = 10; + capacity[1][3] = 4; + capacity[1][4] = 8; + capacity[2][4] = 9; + capacity[3][2] = 6; + capacity[3][4] = 10; + + int maxFlow = FordFulkerson.networkFlow(vertexCount, capacity, flow, 0, 4); + assertEquals(19, maxFlow); + } +}