diff --git a/src/main/java/com/thealgorithms/graph/BronKerbosch.java b/src/main/java/com/thealgorithms/graph/BronKerbosch.java
new file mode 100644
index 000000000000..0510d9bcf494
--- /dev/null
+++ b/src/main/java/com/thealgorithms/graph/BronKerbosch.java
@@ -0,0 +1,114 @@
+package com.thealgorithms.graph;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+/**
+ * Implementation of the Bron–Kerbosch algorithm with pivoting for enumerating all maximal cliques
+ * in an undirected graph.
+ *
+ *
The input graph is represented as an adjacency list where {@code adjacency.get(u)} returns the
+ * set of vertices adjacent to {@code u}. The algorithm runs in time proportional to the number of
+ * maximal cliques produced and is widely used for clique enumeration problems.
+ *
+ * @author Wikipedia: Bron–Kerbosch algorithm
+ */
+public final class BronKerbosch {
+
+ private BronKerbosch() {
+ }
+
+ /**
+ * Finds all maximal cliques of the provided graph.
+ *
+ * @param adjacency adjacency list where {@code adjacency.size()} equals the number of vertices
+ * @return a list containing every maximal clique, each represented as a {@link Set} of vertices
+ * @throws IllegalArgumentException if the adjacency list is {@code null}, contains {@code null}
+ * entries, or references invalid vertices
+ */
+ public static List> findMaximalCliques(List> adjacency) {
+ if (adjacency == null) {
+ throw new IllegalArgumentException("Adjacency list must not be null");
+ }
+
+ int n = adjacency.size();
+ List> graph = new ArrayList<>(n);
+ for (int u = 0; u < n; u++) {
+ Set neighbors = adjacency.get(u);
+ if (neighbors == null) {
+ throw new IllegalArgumentException("Adjacency list must not contain null sets");
+ }
+ Set copy = new HashSet<>();
+ for (int v : neighbors) {
+ if (v < 0 || v >= n) {
+ throw new IllegalArgumentException("Neighbor index out of bounds: " + v);
+ }
+ if (v != u) {
+ copy.add(v);
+ }
+ }
+ graph.add(copy);
+ }
+
+ Set r = new HashSet<>();
+ Set p = new HashSet<>();
+ Set x = new HashSet<>();
+ for (int v = 0; v < n; v++) {
+ p.add(v);
+ }
+
+ List> cliques = new ArrayList<>();
+ bronKerboschPivot(r, p, x, graph, cliques);
+ return cliques;
+ }
+
+ private static void bronKerboschPivot(Set r, Set p, Set x, List> graph, List> cliques) {
+ if (p.isEmpty() && x.isEmpty()) {
+ cliques.add(new HashSet<>(r));
+ return;
+ }
+
+ int pivot = choosePivot(p, x, graph);
+ Set candidates = new HashSet<>(p);
+ if (pivot != -1) {
+ candidates.removeAll(graph.get(pivot));
+ }
+
+ for (Integer v : candidates) {
+ r.add(v);
+ Set newP = intersection(p, graph.get(v));
+ Set newX = intersection(x, graph.get(v));
+ bronKerboschPivot(r, newP, newX, graph, cliques);
+ r.remove(v);
+ p.remove(v);
+ x.add(v);
+ }
+ }
+
+ private static int choosePivot(Set p, Set x, List> graph) {
+ int pivot = -1;
+ int maxDegree = -1;
+ Set union = new HashSet<>(p);
+ union.addAll(x);
+ for (Integer v : union) {
+ int degree = graph.get(v).size();
+ if (degree > maxDegree) {
+ maxDegree = degree;
+ pivot = v;
+ }
+ }
+ return pivot;
+ }
+
+ private static Set intersection(Set base, Set neighbors) {
+ Set result = new HashSet<>();
+ for (Integer v : base) {
+ if (neighbors.contains(v)) {
+ result.add(v);
+ }
+ }
+ return result;
+ }
+}
diff --git a/src/main/java/com/thealgorithms/graph/EdmondsKarp.java b/src/main/java/com/thealgorithms/graph/EdmondsKarp.java
new file mode 100644
index 000000000000..59e7b09cb49c
--- /dev/null
+++ b/src/main/java/com/thealgorithms/graph/EdmondsKarp.java
@@ -0,0 +1,107 @@
+package com.thealgorithms.graph;
+
+import java.util.ArrayDeque;
+import java.util.Arrays;
+import java.util.Queue;
+
+/**
+ * Implementation of the Edmonds–Karp algorithm for computing the maximum flow of a directed graph.
+ *
+ * The algorithm runs in O(V * E^2) time and is a specific implementation of the Ford–Fulkerson
+ * method where the augmenting paths are found using breadth-first search (BFS) to ensure the
+ * shortest augmenting paths (in terms of the number of edges) are used.
+ *
+ *
+ * The graph is represented with a capacity matrix where {@code capacity[u][v]} denotes the
+ * capacity of the edge from {@code u} to {@code v}. Negative capacities are not allowed.
+ *
+ * @author Wikipedia: EdmondsKarp algorithm
+ */
+public final class EdmondsKarp {
+
+ private EdmondsKarp() {
+ }
+
+ /**
+ * Computes the maximum flow from {@code source} to {@code sink} in the provided capacity matrix.
+ *
+ * @param capacity the capacity matrix representing the directed graph; must be square and non-null
+ * @param source the source vertex index
+ * @param sink the sink vertex index
+ * @return the value of the maximum flow between {@code source} and {@code sink}
+ * @throws IllegalArgumentException if the matrix is {@code null}, not square, contains negative
+ * capacities, or if {@code source} / {@code sink} indices are invalid
+ */
+ public static int maxFlow(int[][] capacity, int source, int sink) {
+ if (capacity == null || capacity.length == 0) {
+ throw new IllegalArgumentException("Capacity matrix must not be null or empty");
+ }
+
+ final int n = capacity.length;
+ for (int row = 0; row < n; row++) {
+ if (capacity[row] == null || capacity[row].length != n) {
+ throw new IllegalArgumentException("Capacity matrix must be square");
+ }
+ for (int col = 0; col < n; col++) {
+ if (capacity[row][col] < 0) {
+ throw new IllegalArgumentException("Capacities must be non-negative");
+ }
+ }
+ }
+
+ if (source < 0 || source >= n || sink < 0 || sink >= n) {
+ throw new IllegalArgumentException("Source and sink must be valid vertex indices");
+ }
+ if (source == sink) {
+ return 0;
+ }
+
+ final int[][] residual = new int[n][n];
+ for (int i = 0; i < n; i++) {
+ residual[i] = Arrays.copyOf(capacity[i], n);
+ }
+
+ final int[] parent = new int[n];
+ int maxFlow = 0;
+
+ while (bfs(residual, source, sink, parent)) {
+ int pathFlow = Integer.MAX_VALUE;
+ for (int v = sink; v != source; v = parent[v]) {
+ int u = parent[v];
+ pathFlow = Math.min(pathFlow, residual[u][v]);
+ }
+
+ for (int v = sink; v != source; v = parent[v]) {
+ int u = parent[v];
+ residual[u][v] -= pathFlow;
+ residual[v][u] += pathFlow;
+ }
+
+ maxFlow += pathFlow;
+ }
+
+ return maxFlow;
+ }
+
+ private static boolean bfs(int[][] residual, int source, int sink, int[] parent) {
+ Arrays.fill(parent, -1);
+ parent[source] = source;
+
+ Queue queue = new ArrayDeque<>();
+ queue.add(source);
+
+ while (!queue.isEmpty()) {
+ int u = queue.poll();
+ for (int v = 0; v < residual.length; v++) {
+ if (residual[u][v] > 0 && parent[v] == -1) {
+ parent[v] = u;
+ if (v == sink) {
+ return true;
+ }
+ queue.add(v);
+ }
+ }
+ }
+ return false;
+ }
+}
diff --git a/src/test/java/com/thealgorithms/graph/BronKerboschTest.java b/src/test/java/com/thealgorithms/graph/BronKerboschTest.java
new file mode 100644
index 000000000000..54c91c6ac1fd
--- /dev/null
+++ b/src/test/java/com/thealgorithms/graph/BronKerboschTest.java
@@ -0,0 +1,79 @@
+package com.thealgorithms.graph;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import java.util.ArrayList;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+class BronKerboschTest {
+
+ @Test
+ @DisplayName("Complete graph returns single clique")
+ void completeGraph() {
+ List> adjacency = buildGraph(4);
+ addUndirectedEdge(adjacency, 0, 1);
+ addUndirectedEdge(adjacency, 0, 2);
+ addUndirectedEdge(adjacency, 0, 3);
+ addUndirectedEdge(adjacency, 1, 2);
+ addUndirectedEdge(adjacency, 1, 3);
+ addUndirectedEdge(adjacency, 2, 3);
+
+ List> cliques = BronKerbosch.findMaximalCliques(adjacency);
+ assertEquals(1, cliques.size());
+ assertEquals(Set.of(0, 1, 2, 3), cliques.get(0));
+ }
+
+ @Test
+ @DisplayName("Path graph produces individual edges")
+ void pathGraph() {
+ List> adjacency = buildGraph(3);
+ addUndirectedEdge(adjacency, 0, 1);
+ addUndirectedEdge(adjacency, 1, 2);
+
+ List> cliques = BronKerbosch.findMaximalCliques(adjacency);
+ Set> result = new HashSet<>(cliques);
+ Set> expected = Set.of(Set.of(0, 1), Set.of(1, 2));
+ assertEquals(expected, result);
+ }
+
+ @Test
+ @DisplayName("Disconnected graph finds cliques per component")
+ void disconnectedGraph() {
+ List> adjacency = buildGraph(5);
+ addUndirectedEdge(adjacency, 0, 1);
+ addUndirectedEdge(adjacency, 0, 2);
+ addUndirectedEdge(adjacency, 1, 2);
+ addUndirectedEdge(adjacency, 3, 4);
+
+ List> cliques = BronKerbosch.findMaximalCliques(adjacency);
+ Set> result = new HashSet<>(cliques);
+ Set> expected = Set.of(Set.of(0, 1, 2), Set.of(3, 4));
+ assertEquals(expected, result);
+ }
+
+ @Test
+ @DisplayName("Null neighbor set triggers exception")
+ void nullNeighborSet() {
+ List> adjacency = new ArrayList<>();
+ adjacency.add(null);
+ assertThrows(IllegalArgumentException.class, () -> BronKerbosch.findMaximalCliques(adjacency));
+ }
+
+ private static List> buildGraph(int n) {
+ List> graph = new ArrayList<>(n);
+ for (int i = 0; i < n; i++) {
+ graph.add(new HashSet<>());
+ }
+ return graph;
+ }
+
+ private static void addUndirectedEdge(List> graph, int u, int v) {
+ graph.get(u).add(v);
+ graph.get(v).add(u);
+ }
+}
diff --git a/src/test/java/com/thealgorithms/graph/EdmondsKarpTest.java b/src/test/java/com/thealgorithms/graph/EdmondsKarpTest.java
new file mode 100644
index 000000000000..55aeda381031
--- /dev/null
+++ b/src/test/java/com/thealgorithms/graph/EdmondsKarpTest.java
@@ -0,0 +1,48 @@
+package com.thealgorithms.graph;
+
+import static org.junit.jupiter.api.Assertions.assertEquals;
+import static org.junit.jupiter.api.Assertions.assertThrows;
+
+import org.junit.jupiter.api.DisplayName;
+import org.junit.jupiter.api.Test;
+
+class EdmondsKarpTest {
+
+ @Test
+ @DisplayName("Classic CLRS network yields max flow 23")
+ void clrsExample() {
+ int[][] capacity = {{0, 16, 13, 0, 0, 0}, {0, 0, 10, 12, 0, 0}, {0, 4, 0, 0, 14, 0}, {0, 0, 9, 0, 0, 20}, {0, 0, 0, 7, 0, 4}, {0, 0, 0, 0, 0, 0}};
+ int maxFlow = EdmondsKarp.maxFlow(capacity, 0, 5);
+ assertEquals(23, maxFlow);
+ }
+
+ @Test
+ @DisplayName("Disconnected network has zero flow")
+ void disconnectedGraph() {
+ int[][] capacity = {{0, 0, 0}, {0, 0, 0}, {0, 0, 0}};
+ int maxFlow = EdmondsKarp.maxFlow(capacity, 0, 2);
+ assertEquals(0, maxFlow);
+ }
+
+ @Test
+ @DisplayName("Source equals sink returns zero")
+ void sourceEqualsSink() {
+ int[][] capacity = {{0, 5}, {0, 0}};
+ int maxFlow = EdmondsKarp.maxFlow(capacity, 0, 0);
+ assertEquals(0, maxFlow);
+ }
+
+ @Test
+ @DisplayName("Invalid matrix throws exception")
+ void invalidMatrix() {
+ int[][] capacity = {{0, 1}, {1}};
+ assertThrows(IllegalArgumentException.class, () -> EdmondsKarp.maxFlow(capacity, 0, 1));
+ }
+
+ @Test
+ @DisplayName("Negative capacity is rejected")
+ void negativeCapacity() {
+ int[][] capacity = {{0, -1}, {0, 0}};
+ assertThrows(IllegalArgumentException.class, () -> EdmondsKarp.maxFlow(capacity, 0, 1));
+ }
+}