From 5963b423fde8e9c7ab97910f0801db6cc807c752 Mon Sep 17 00:00:00 2001 From: TarunVishwakarma1 Date: Tue, 24 Sep 2024 15:11:45 +0000 Subject: [PATCH 01/28] Update directory --- DIRECTORY.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index bbcee88e52be..0e96e8fb22bf 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -560,6 +560,7 @@ * [LongestNonRepetitiveSubstring](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/LongestNonRepetitiveSubstring.java) * [LongestPalindromicSubstring](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/LongestPalindromicSubstring.java) * [Lower](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Lower.java) + * [Manacher](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Manacher.java) * [MyAtoi](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/MyAtoi.java) * [Palindrome](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Palindrome.java) * [Pangram](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/strings/Pangram.java) @@ -846,6 +847,8 @@ * [TwinPrimeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/TwinPrimeTest.java) * [VolumeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/maths/VolumeTest.java) * misc + * [ColorContrastRatioTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/ColorContrastRatioTest.java) + * [InverseOfMatrixTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/InverseOfMatrixTest.java) * [MapReduceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/MapReduceTest.java) * [MedianOfMatrixtest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/MedianOfMatrixtest.java) * [MedianOfRunningArrayTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/misc/MedianOfRunningArrayTest.java) @@ -857,6 +860,7 @@ * [ArrayRightRotation](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/ArrayRightRotation.java) * [ArrayRightRotationTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/ArrayRightRotationTest.java) * [BestFitCPUTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/BestFitCPUTest.java) + * [BFPRTTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/BFPRTTest.java) * [BoyerMooreTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/BoyerMooreTest.java) * cn * [HammingDistanceTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/others/cn/HammingDistanceTest.java) @@ -976,6 +980,7 @@ * [LongestNonRepetitiveSubstringTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/LongestNonRepetitiveSubstringTest.java) * [LongestPalindromicSubstringTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/LongestPalindromicSubstringTest.java) * [LowerTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/LowerTest.java) + * [ManacherTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/ManacherTest.java) * [MyAtoiTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/MyAtoiTest.java) * [PalindromeTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/PalindromeTest.java) * [PangramTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/strings/PangramTest.java) From 11eb3bc95dfd299993f0679a12d933234bb57633 Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Tue, 24 Sep 2024 23:30:49 +0530 Subject: [PATCH 02/28] Implement Edmonds' Blossom Algorithm for maximum matching in general graphs with test cases and improved output formatting. --- .../graphs/EdmondsBlossomAlgorithm.java | 253 ++++++++++++++++++ 1 file changed, 253 insertions(+) create mode 100644 src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java new file mode 100644 index 000000000000..45cdc3a790cf --- /dev/null +++ b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java @@ -0,0 +1,253 @@ +package com.thealgorithms.datastructures.graphs; + +import java.util.*; + +/** + * The EdmondsBlossomAlgorithm class implements Edmonds' Blossom Algorithm + * to find the maximum matching in a general graph. The algorithm efficiently + * handles cases where the graph contains odd-length cycles by contracting + * "blossoms" and finding augmenting paths. + *

+ * The maximum matching problem seeks to find the largest set of vertex pairs + * such that no vertex is part of more than one pair, which is especially useful + * in graph theory problems like job assignments, scheduling, and network flows. + *

+ * The algorithm follows these main steps: + * - Builds the graph using an adjacency list from input edges. + * - Uses a breadth-first search (BFS) to find augmenting paths. + * - Contracts blossoms (odd-length cycles) that prevent straightforward path + * finding, allowing the algorithm to continue exploring augmenting paths. + * - Updates the matching whenever an augmenting path is found. + *

+ * This implementation supports the following features: + * - Handling general graphs (not restricted to bipartite graphs). + * - Finding augmenting paths using BFS. + * - Contracting blossoms to overcome odd-length cycles. + * - Returning the list of matched vertex pairs. + *

+ * Example: + * For a triangle graph with edges {(0, 1), (1, 2), (2, 0)}, the algorithm + * would find a maximum matching like {(0, 1)}, where vertex 2 is unmatched. + *

+ * This class includes test cases in the main method to demonstrate how + * the algorithm works on different graph structures, such as simple triangles, + * squares, bipartite graphs, and graphs with more edges than vertices. + */ + + +public class EdmondsBlossomAlgorithm { + + private static final int UNMATCHED = -1; + + /** + * Finds the maximum matching in a general graph (Edmonds Blossom Algorithm). + * + * @param edges A list of edges in the graph. + * @param vertexCount The number of vertices in the graph. + * @return A list of matched pairs of vertices. + */ + public static List maximumMatching(List edges, int vertexCount) { + // Create adjacency list to represent the graph + List[] graph = new ArrayList[vertexCount]; + for (int i = 0; i < vertexCount; i++) { + graph[i] = new ArrayList<>(); + } + + // Populate the graph with the edges + for (int[] edge : edges) { + int u = edge[0]; + int v = edge[1]; + graph[u].add(v); + graph[v].add(u); + } + + // Initial matching array and auxiliary data structures + int[] match = new int[vertexCount]; + Arrays.fill(match, UNMATCHED); // All vertices are initially unmatched + int[] parent = new int[vertexCount]; + int[] base = new int[vertexCount]; + boolean[] inBlossom = new boolean[vertexCount]; // Indicates if a vertex is part of a blossom + boolean[] inQueue = new boolean[vertexCount]; // Tracks vertices in the BFS queue + + // Main logic for finding maximum matching + for (int u = 0; u < vertexCount; u++) { + if (match[u] == UNMATCHED) { + // BFS initialization + Arrays.fill(parent, UNMATCHED); + for (int i = 0; i < vertexCount; i++) base[i] = i; + Arrays.fill(inBlossom, false); + Arrays.fill(inQueue, false); + + Queue queue = new LinkedList<>(); + queue.add(u); + inQueue[u] = true; + + boolean augmentingPathFound = false; + + // BFS to find augmenting paths + while (!queue.isEmpty() && !augmentingPathFound) { + int x = queue.poll(); + + for (int y : graph[x]) { + // Skip if we are looking at the same edge as the current match + if (match[x] == y) continue; + + if (base[x] == base[y]) continue; // Avoid self-loops + + if (parent[y] == UNMATCHED) { + // Case 1: y is unmatched, we've found an augmenting path + if (match[y] == UNMATCHED) { + parent[y] = x; + augmentingPathFound = true; + updateMatching(match, parent, y); // Augment along this path + break; + } + + // Case 2: y is matched, add y's match to the queue + int z = match[y]; + parent[y] = x; + parent[z] = y; + if (!inQueue[z]) { + queue.add(z); + inQueue[z] = true; + } + } else { + // Case 3: Both x and y have a parent; check for a cycle/blossom + int baseU = findBase(base, parent, x, y); + if (baseU != UNMATCHED) { + contractBlossom(queue, parent, base, inBlossom, match, inQueue, x, y, baseU); + } + } + } + } + } + } + + // Create result list of matched pairs + List matchingResult = new ArrayList<>(); + for (int v = 0; v < vertexCount; v++) { + if (match[v] != UNMATCHED && v < match[v]) { + matchingResult.add(new int[]{v, match[v]}); + } + } + + return matchingResult; + } + + /** + * Updates the matching along the augmenting path found. + * + * @param match The matching array. + * @param parent The parent array used during the BFS. + * @param u The starting node of the augmenting path. + */ + private static void updateMatching(int[] match, int[] parent, int u) { + while (u != UNMATCHED) { + int v = parent[u]; + int next = match[v]; + match[v] = u; + match[u] = v; + u = next; + } + } + + /** + * Finds the base of a node in the blossom. + * + * @param base The base array. + * @param parent The parent array. + * @param u One end of the edge. + * @param v The other end of the edge. + * @return The base of the node or UNMATCHED. + */ + private static int findBase(int[] base, int[] parent, int u, int v) { + boolean[] visited = new boolean[base.length]; + + // Mark ancestors of u + while (true) { + u = base[u]; + visited[u] = true; + if (parent[u] == UNMATCHED) break; + u = parent[u]; + } + + // Find the common ancestor of v + while (true) { + v = base[v]; + if (visited[v]) return v; // The first visited node is the lowest common ancestor + v = parent[v]; + } + } + + /** + * Contracts a blossom and updates the base array. + * + * @param queue The BFS queue. + * @param parent The parent array. + * @param base The base array. + * @param inBlossom The blossom array. + * @param match The matching array. + * @param inQueue The inQueue array. + * @param u One node in the blossom. + * @param v The other node in the blossom. + * @param lca The lowest common ancestor. + */ + private static void contractBlossom(Queue queue, int[] parent, int[] base, boolean[] inBlossom, int[] match, boolean[] inQueue, int u, int v, int lca) { + for (int x = u; base[x] != lca; x = parent[match[x]]) { + inBlossom[base[x]] = inBlossom[base[match[x]]] = true; + } + for (int x = v; base[x] != lca; x = parent[match[x]]) { + inBlossom[base[x]] = inBlossom[base[match[x]]] = true; + } + + for (int i = 0; i < base.length; i++) { + if (inBlossom[base[i]]) { + base[i] = lca; + if (!inQueue[i]) { + queue.add(i); + inQueue[i] = true; + } + } + } + } + + /** + * Helper method to print the matching results in a readable format. + * + * @param testCase The name of the test case being executed. + * @param matching The list of matched pairs of vertices. + */ + private static void printMatchingResult(String testCase, List matching) { + System.out.print(testCase + ": "); + for (int[] match : matching) { + System.out.print(Arrays.toString(match) + " "); + } + System.out.println(); + } + +// public static void main(String[] args) { +// runTests(); +// } + + public static void runTests() { + // Test Case 1: Simple triangle + List edges1 = Arrays.asList(new int[]{0, 1}, new int[]{1, 2}, new int[]{2, 0}); + int vertexCount1 = 3; + printMatchingResult("Test Case 1: " , maximumMatching(edges1, vertexCount1)); + + // Test Case 2: Square shape + List edges2 = Arrays.asList(new int[]{0, 1}, new int[]{1, 2}, new int[]{2, 3}, new int[]{3, 0}); + int vertexCount2 = 4; + printMatchingResult("Test Case 2: " , maximumMatching(edges2, vertexCount2)); + + // Test Case 3: Bipartite graph + List edges3 = Arrays.asList(new int[]{0, 2}, new int[]{0, 3}, new int[]{1, 2}, new int[]{1, 3}); + int vertexCount3 = 4; + printMatchingResult("Test Case 3: " , maximumMatching(edges3, vertexCount3)); + + // Test Case 4: More edges than vertices + List edges4 = Arrays.asList(new int[]{0, 1}, new int[]{1, 2}, new int[]{0, 2}, new int[]{1, 3}, new int[]{2, 3}); + int vertexCount4 = 4; + printMatchingResult("Test Case 4: " , maximumMatching(edges4, vertexCount4)); + } +} From 036983a68138c79273e8cf3aca81ff0efb2f7310 Mon Sep 17 00:00:00 2001 From: TarunVishwakarma1 Date: Tue, 24 Sep 2024 18:01:38 +0000 Subject: [PATCH 03/28] Update directory --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 0e96e8fb22bf..08f91cbd7ff8 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -107,6 +107,7 @@ * [ConnectedComponent](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/ConnectedComponent.java) * [Cycles](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/Cycles.java) * [DijkstraAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithm.java) + * [EdmondsBlossomAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java) * [FloydWarshall](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/FloydWarshall.java) * [FordFulkerson](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/FordFulkerson.java) * [Graphs](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/Graphs.java) From 096dee9737188802ceedd3c08e3b004c02d591c8 Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Tue, 24 Sep 2024 23:38:19 +0530 Subject: [PATCH 04/28] Added github path for EdmondsBlossomAlgorith.java in the src/main/java/com/thealgorithms/datastructures/graphs --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 0e96e8fb22bf..f6496187b1c3 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -107,6 +107,7 @@ * [ConnectedComponent](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/ConnectedComponent.java) * [Cycles](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/Cycles.java) * [DijkstraAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithm.java) + * [EdmondsBlossomAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithms.java) * [FloydWarshall](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/FloydWarshall.java) * [FordFulkerson](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/FordFulkerson.java) * [Graphs](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/Graphs.java) From 6962cf789ec5bd05945da9e1a51a093d4fccbcee Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Tue, 24 Sep 2024 23:56:40 +0530 Subject: [PATCH 05/28] Fixed some build errors --- .../graphs/EdmondsBlossomAlgorithm.java | 31 +++++++++++++------ 1 file changed, 22 insertions(+), 9 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java index 45cdc3a790cf..1230789ad49a 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java @@ -1,5 +1,6 @@ package com.thealgorithms.datastructures.graphs; + import java.util.*; /** @@ -37,6 +38,8 @@ public class EdmondsBlossomAlgorithm { + private EdmondsBlossomAlgorithm(){} + private static final int UNMATCHED = -1; /** @@ -74,7 +77,9 @@ public static List maximumMatching(List edges, int vertexCount) { if (match[u] == UNMATCHED) { // BFS initialization Arrays.fill(parent, UNMATCHED); - for (int i = 0; i < vertexCount; i++) base[i] = i; + for (int i = 0; i < vertexCount; i++){ + base[i] = i; + } Arrays.fill(inBlossom, false); Arrays.fill(inQueue, false); @@ -90,9 +95,13 @@ public static List maximumMatching(List edges, int vertexCount) { for (int y : graph[x]) { // Skip if we are looking at the same edge as the current match - if (match[x] == y) continue; + if (match[x] == y) { + continue; + } - if (base[x] == base[y]) continue; // Avoid self-loops + if (base[x] == base[y]) { + continue; // Avoid self-loops + } if (parent[y] == UNMATCHED) { // Case 1: y is unmatched, we've found an augmenting path @@ -167,14 +176,18 @@ private static int findBase(int[] base, int[] parent, int u, int v) { while (true) { u = base[u]; visited[u] = true; - if (parent[u] == UNMATCHED) break; + if (parent[u] == UNMATCHED) { + break; + } u = parent[u]; } // Find the common ancestor of v while (true) { v = base[v]; - if (visited[v]) return v; // The first visited node is the lowest common ancestor + if (visited[v]) { + return v; // The first visited node is the lowest common ancestor + } v = parent[v]; } } @@ -233,21 +246,21 @@ public static void runTests() { // Test Case 1: Simple triangle List edges1 = Arrays.asList(new int[]{0, 1}, new int[]{1, 2}, new int[]{2, 0}); int vertexCount1 = 3; - printMatchingResult("Test Case 1: " , maximumMatching(edges1, vertexCount1)); + printMatchingResult("Test Case 1: ", maximumMatching(edges1, vertexCount1)); // Test Case 2: Square shape List edges2 = Arrays.asList(new int[]{0, 1}, new int[]{1, 2}, new int[]{2, 3}, new int[]{3, 0}); int vertexCount2 = 4; - printMatchingResult("Test Case 2: " , maximumMatching(edges2, vertexCount2)); + printMatchingResult("Test Case 2: ", maximumMatching(edges2, vertexCount2)); // Test Case 3: Bipartite graph List edges3 = Arrays.asList(new int[]{0, 2}, new int[]{0, 3}, new int[]{1, 2}, new int[]{1, 3}); int vertexCount3 = 4; - printMatchingResult("Test Case 3: " , maximumMatching(edges3, vertexCount3)); + printMatchingResult("Test Case 3: ", maximumMatching(edges3, vertexCount3)); // Test Case 4: More edges than vertices List edges4 = Arrays.asList(new int[]{0, 1}, new int[]{1, 2}, new int[]{0, 2}, new int[]{1, 3}, new int[]{2, 3}); int vertexCount4 = 4; - printMatchingResult("Test Case 4: " , maximumMatching(edges4, vertexCount4)); + printMatchingResult("Test Case 4: ", maximumMatching(edges4, vertexCount4)); } } From 324cf61aa39c6fabba74603c444d686503f0c370 Mon Sep 17 00:00:00 2001 From: TarunVishwakarma1 Date: Tue, 24 Sep 2024 18:27:16 +0000 Subject: [PATCH 06/28] Update directory --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 0e96e8fb22bf..08f91cbd7ff8 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -107,6 +107,7 @@ * [ConnectedComponent](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/ConnectedComponent.java) * [Cycles](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/Cycles.java) * [DijkstraAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithm.java) + * [EdmondsBlossomAlgorithm](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java) * [FloydWarshall](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/FloydWarshall.java) * [FordFulkerson](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/FordFulkerson.java) * [Graphs](https://github.com/TheAlgorithms/Java/blob/master/src/main/java/com/thealgorithms/datastructures/graphs/Graphs.java) From 00b18dcf3c605f90528f8fdc0b8e5cf88f107841 Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Wed, 25 Sep 2024 00:06:04 +0530 Subject: [PATCH 07/28] Fixed Cland-style --- .../graphs/EdmondsBlossomAlgorithm.java | 25 ++++++++----------- 1 file changed, 11 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java index 1230789ad49a..ee1b89bb4257 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java @@ -66,18 +66,18 @@ public static List maximumMatching(List edges, int vertexCount) { // Initial matching array and auxiliary data structures int[] match = new int[vertexCount]; - Arrays.fill(match, UNMATCHED); // All vertices are initially unmatched + Arrays.fill(match, UNMATCHED); // All vertices are initially unmatched int[] parent = new int[vertexCount]; int[] base = new int[vertexCount]; - boolean[] inBlossom = new boolean[vertexCount]; // Indicates if a vertex is part of a blossom - boolean[] inQueue = new boolean[vertexCount]; // Tracks vertices in the BFS queue + boolean[] inBlossom = new boolean[vertexCount]; // Indicates if a vertex is part of a blossom + boolean[] inQueue = new boolean[vertexCount]; // Tracks vertices in the BFS queue // Main logic for finding maximum matching for (int u = 0; u < vertexCount; u++) { if (match[u] == UNMATCHED) { // BFS initialization Arrays.fill(parent, UNMATCHED); - for (int i = 0; i < vertexCount; i++){ + for (int i = 0; i < vertexCount; i++) { base[i] = i; } Arrays.fill(inBlossom, false); @@ -100,7 +100,7 @@ public static List maximumMatching(List edges, int vertexCount) { } if (base[x] == base[y]) { - continue; // Avoid self-loops + continue; // Avoid self-loops } if (parent[y] == UNMATCHED) { @@ -108,7 +108,7 @@ public static List maximumMatching(List edges, int vertexCount) { if (match[y] == UNMATCHED) { parent[y] = x; augmentingPathFound = true; - updateMatching(match, parent, y); // Augment along this path + updateMatching(match, parent, y); // Augment along this path break; } @@ -186,7 +186,7 @@ private static int findBase(int[] base, int[] parent, int u, int v) { while (true) { v = base[v]; if (visited[v]) { - return v; // The first visited node is the lowest common ancestor + return v; // The first visited node is the lowest common ancestor } v = parent[v]; } @@ -238,28 +238,25 @@ private static void printMatchingResult(String testCase, List matching) { System.out.println(); } -// public static void main(String[] args) { -// runTests(); -// } public static void runTests() { // Test Case 1: Simple triangle - List edges1 = Arrays.asList(new int[]{0, 1}, new int[]{1, 2}, new int[]{2, 0}); + List edges1 = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 0}); int vertexCount1 = 3; printMatchingResult("Test Case 1: ", maximumMatching(edges1, vertexCount1)); // Test Case 2: Square shape - List edges2 = Arrays.asList(new int[]{0, 1}, new int[]{1, 2}, new int[]{2, 3}, new int[]{3, 0}); + List edges2 = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 3}, new int[] {3, 0}); int vertexCount2 = 4; printMatchingResult("Test Case 2: ", maximumMatching(edges2, vertexCount2)); // Test Case 3: Bipartite graph - List edges3 = Arrays.asList(new int[]{0, 2}, new int[]{0, 3}, new int[]{1, 2}, new int[]{1, 3}); + List edges3 = Arrays.asList(new int[] {0, 2}, new int[] {0, 3}, new int[] {1, 2}, new int[] {1, 3}); int vertexCount3 = 4; printMatchingResult("Test Case 3: ", maximumMatching(edges3, vertexCount3)); // Test Case 4: More edges than vertices - List edges4 = Arrays.asList(new int[]{0, 1}, new int[]{1, 2}, new int[]{0, 2}, new int[]{1, 3}, new int[]{2, 3}); + List edges4 = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {0, 2}, new int[] {1, 3}, new int[] {2, 3}); int vertexCount4 = 4; printMatchingResult("Test Case 4: ", maximumMatching(edges4, vertexCount4)); } From 82d45fd306ceac1c9214848c0a637335da92cac7 Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Wed, 25 Sep 2024 00:09:50 +0530 Subject: [PATCH 08/28] Fixed Cland-style --- .../datastructures/graphs/EdmondsBlossomAlgorithm.java | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java index ee1b89bb4257..8e6c3b5a2c24 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java @@ -38,7 +38,8 @@ public class EdmondsBlossomAlgorithm { - private EdmondsBlossomAlgorithm(){} + private EdmondsBlossomAlgorithm() { + } private static final int UNMATCHED = -1; @@ -136,7 +137,7 @@ public static List maximumMatching(List edges, int vertexCount) { List matchingResult = new ArrayList<>(); for (int v = 0; v < vertexCount; v++) { if (match[v] != UNMATCHED && v < match[v]) { - matchingResult.add(new int[]{v, match[v]}); + matchingResult.add(new int[] {v, match[v]}); } } From 6b6a0931248a77f0f8d1a91eaa244acf48cc99ea Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Wed, 25 Sep 2024 00:46:16 +0530 Subject: [PATCH 09/28] Fixed import statement --- .../graphs/EdmondsBlossomAlgorithm.java | 48 +++++++++---------- 1 file changed, 24 insertions(+), 24 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java index 8e6c3b5a2c24..bee540f3e36f 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java @@ -1,7 +1,10 @@ package com.thealgorithms.datastructures.graphs; - -import java.util.*; +import java.util.Arrays; +import java.util.List; +import java.util.ArrayList; +import java.util.Queue; +import java.util.LinkedList; /** * The EdmondsBlossomAlgorithm class implements Edmonds' Blossom Algorithm @@ -13,13 +16,6 @@ * such that no vertex is part of more than one pair, which is especially useful * in graph theory problems like job assignments, scheduling, and network flows. *

- * The algorithm follows these main steps: - * - Builds the graph using an adjacency list from input edges. - * - Uses a breadth-first search (BFS) to find augmenting paths. - * - Contracts blossoms (odd-length cycles) that prevent straightforward path - * finding, allowing the algorithm to continue exploring augmenting paths. - * - Updates the matching whenever an augmenting path is found. - *

* This implementation supports the following features: * - Handling general graphs (not restricted to bipartite graphs). * - Finding augmenting paths using BFS. @@ -34,11 +30,10 @@ * the algorithm works on different graph structures, such as simple triangles, * squares, bipartite graphs, and graphs with more edges than vertices. */ - - -public class EdmondsBlossomAlgorithm { +public final class EdmondsBlossomAlgorithm { private EdmondsBlossomAlgorithm() { + // Prevent instantiation of the utility class } private static final int UNMATCHED = -1; @@ -71,7 +66,7 @@ public static List maximumMatching(List edges, int vertexCount) { int[] parent = new int[vertexCount]; int[] base = new int[vertexCount]; boolean[] inBlossom = new boolean[vertexCount]; // Indicates if a vertex is part of a blossom - boolean[] inQueue = new boolean[vertexCount]; // Tracks vertices in the BFS queue + boolean[] inQueue = new boolean[vertexCount]; // Tracks vertices in the BFS queue // Main logic for finding maximum matching for (int u = 0; u < vertexCount; u++) { @@ -79,7 +74,7 @@ public static List maximumMatching(List edges, int vertexCount) { // BFS initialization Arrays.fill(parent, UNMATCHED); for (int i = 0; i < vertexCount; i++) { - base[i] = i; + base[i] = i; // Each vertex is its own base initially } Arrays.fill(inBlossom, false); Arrays.fill(inQueue, false); @@ -206,19 +201,22 @@ private static int findBase(int[] base, int[] parent, int u, int v) { * @param v The other node in the blossom. * @param lca The lowest common ancestor. */ - private static void contractBlossom(Queue queue, int[] parent, int[] base, boolean[] inBlossom, int[] match, boolean[] inQueue, int u, int v, int lca) { + private static void contractBlossom(Queue queue, int[] parent, int[] base, + boolean[] inBlossom, int[] match, boolean[] inQueue, + int u, int v, int lca) { for (int x = u; base[x] != lca; x = parent[match[x]]) { - inBlossom[base[x]] = inBlossom[base[match[x]]] = true; + inBlossom[base[x]] = inBlossom[base[match[x]]] = true; // Mark blossom vertices } for (int x = v; base[x] != lca; x = parent[match[x]]) { - inBlossom[base[x]] = inBlossom[base[match[x]]] = true; + inBlossom[base[x]] = inBlossom[base[match[x]]] = true; // Mark blossom vertices } + // Update the base for all marked vertices for (int i = 0; i < base.length; i++) { if (inBlossom[base[i]]) { - base[i] = lca; + base[i] = lca; // Contract to the lowest common ancestor if (!inQueue[i]) { - queue.add(i); + queue.add(i); // Add to queue if not already present inQueue[i] = true; } } @@ -239,26 +237,28 @@ private static void printMatchingResult(String testCase, List matching) { System.out.println(); } - + /** + * Runs test cases to demonstrate the functionality of the algorithm. + */ public static void runTests() { // Test Case 1: Simple triangle List edges1 = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 0}); int vertexCount1 = 3; - printMatchingResult("Test Case 1: ", maximumMatching(edges1, vertexCount1)); + printMatchingResult("Test Case 1", maximumMatching(edges1, vertexCount1)); // Test Case 2: Square shape List edges2 = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 3}, new int[] {3, 0}); int vertexCount2 = 4; - printMatchingResult("Test Case 2: ", maximumMatching(edges2, vertexCount2)); + printMatchingResult("Test Case 2", maximumMatching(edges2, vertexCount2)); // Test Case 3: Bipartite graph List edges3 = Arrays.asList(new int[] {0, 2}, new int[] {0, 3}, new int[] {1, 2}, new int[] {1, 3}); int vertexCount3 = 4; - printMatchingResult("Test Case 3: ", maximumMatching(edges3, vertexCount3)); + printMatchingResult("Test Case 3", maximumMatching(edges3, vertexCount3)); // Test Case 4: More edges than vertices List edges4 = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {0, 2}, new int[] {1, 3}, new int[] {2, 3}); int vertexCount4 = 4; - printMatchingResult("Test Case 4: ", maximumMatching(edges4, vertexCount4)); + printMatchingResult("Test Case 4", maximumMatching(edges4, vertexCount4)); } } From 9eb94bbed1fd9d1fde558d7b8e361f33f9e46361 Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Wed, 25 Sep 2024 00:49:49 +0530 Subject: [PATCH 10/28] Clang Format Fix --- .../datastructures/graphs/EdmondsBlossomAlgorithm.java | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java index bee540f3e36f..d8c09a208191 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java @@ -1,10 +1,10 @@ package com.thealgorithms.datastructures.graphs; +import java.util.ArrayList; import java.util.Arrays; import java.util.List; -import java.util.ArrayList; -import java.util.Queue; import java.util.LinkedList; +import java.util.Queue; /** * The EdmondsBlossomAlgorithm class implements Edmonds' Blossom Algorithm @@ -66,7 +66,7 @@ public static List maximumMatching(List edges, int vertexCount) { int[] parent = new int[vertexCount]; int[] base = new int[vertexCount]; boolean[] inBlossom = new boolean[vertexCount]; // Indicates if a vertex is part of a blossom - boolean[] inQueue = new boolean[vertexCount]; // Tracks vertices in the BFS queue + boolean[] inQueue = new boolean[vertexCount]; // Tracks vertices in the BFS queue // Main logic for finding maximum matching for (int u = 0; u < vertexCount; u++) { @@ -201,9 +201,7 @@ private static int findBase(int[] base, int[] parent, int u, int v) { * @param v The other node in the blossom. * @param lca The lowest common ancestor. */ - private static void contractBlossom(Queue queue, int[] parent, int[] base, - boolean[] inBlossom, int[] match, boolean[] inQueue, - int u, int v, int lca) { + private static void contractBlossom(Queue queue, int[] parent, int[] base, boolean[] inBlossom, int[] match, boolean[] inQueue, int u, int v, int lca) { for (int x = u; base[x] != lca; x = parent[match[x]]) { inBlossom[base[x]] = inBlossom[base[match[x]]] = true; // Mark blossom vertices } From 7bfc1518349bc9e26f4f7f60be83f99b9743f2c3 Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Wed, 25 Sep 2024 00:59:30 +0530 Subject: [PATCH 11/28] Fix CheckStyle issues --- .../graphs/EdmondsBlossomAlgorithm.java | 104 +++++++++++------- 1 file changed, 62 insertions(+), 42 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java index d8c09a208191..ad50f7538627 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java @@ -45,7 +45,7 @@ private EdmondsBlossomAlgorithm() { * @param vertexCount The number of vertices in the graph. * @return A list of matched pairs of vertices. */ - public static List maximumMatching(List edges, int vertexCount) { + public List maximumMatching(List edges, int vertexCount) { // Create adjacency list to represent the graph List[] graph = new ArrayList[vertexCount]; for (int i = 0; i < vertexCount; i++) { @@ -87,22 +87,21 @@ public static List maximumMatching(List edges, int vertexCount) { // BFS to find augmenting paths while (!queue.isEmpty() && !augmentingPathFound) { - int x = queue.poll(); - - for (int y : graph[x]) { + int current = queue.poll(); // Use a different name for clarity + for (int y : graph[current]) { // Skip if we are looking at the same edge as the current match - if (match[x] == y) { + if (match[current] == y) { continue; } - if (base[x] == base[y]) { + if (base[current] == base[y]) { continue; // Avoid self-loops } if (parent[y] == UNMATCHED) { // Case 1: y is unmatched, we've found an augmenting path if (match[y] == UNMATCHED) { - parent[y] = x; + parent[y] = current; augmentingPathFound = true; updateMatching(match, parent, y); // Augment along this path break; @@ -110,7 +109,7 @@ public static List maximumMatching(List edges, int vertexCount) { // Case 2: y is matched, add y's match to the queue int z = match[y]; - parent[y] = x; + parent[y] = current; parent[z] = y; if (!inQueue[z]) { queue.add(z); @@ -118,9 +117,9 @@ public static List maximumMatching(List edges, int vertexCount) { } } else { // Case 3: Both x and y have a parent; check for a cycle/blossom - int baseU = findBase(base, parent, x, y); + int baseU = findBase(base, parent, current, y); if (baseU != UNMATCHED) { - contractBlossom(queue, parent, base, inBlossom, match, inQueue, x, y, baseU); + contractBlossom(new BlossomData(queue, parent, base, inBlossom, match, inQueue, current, y, baseU)); } } } @@ -169,53 +168,47 @@ private static int findBase(int[] base, int[] parent, int u, int v) { boolean[] visited = new boolean[base.length]; // Mark ancestors of u + int currentU = u; // Use a temporary variable while (true) { - u = base[u]; - visited[u] = true; - if (parent[u] == UNMATCHED) { + currentU = base[currentU]; // Assign to the temporary variable + visited[currentU] = true; // Mark as visited + if (parent[currentU] == UNMATCHED) { break; } - u = parent[u]; + currentU = parent[currentU]; // Reassign to the temporary variable } // Find the common ancestor of v + int currentV = v; // Use a temporary variable while (true) { - v = base[v]; - if (visited[v]) { - return v; // The first visited node is the lowest common ancestor + currentV = base[currentV]; // Assign to the temporary variable + if (visited[currentV]) { + return currentV; // The first visited node is the lowest common ancestor } - v = parent[v]; + currentV = parent[currentV]; // Reassign to the temporary variable } } /** * Contracts a blossom and updates the base array. * - * @param queue The BFS queue. - * @param parent The parent array. - * @param base The base array. - * @param inBlossom The blossom array. - * @param match The matching array. - * @param inQueue The inQueue array. - * @param u One node in the blossom. - * @param v The other node in the blossom. - * @param lca The lowest common ancestor. + * @param blossomData The data containing the parameters related to the blossom contraction. */ - private static void contractBlossom(Queue queue, int[] parent, int[] base, boolean[] inBlossom, int[] match, boolean[] inQueue, int u, int v, int lca) { - for (int x = u; base[x] != lca; x = parent[match[x]]) { - inBlossom[base[x]] = inBlossom[base[match[x]]] = true; // Mark blossom vertices + private static void contractBlossom(BlossomData blossomData) { + for (int x = blossomData.u; blossomData.base[x] != blossomData.lca; x = blossomData.parent[blossomData.match[x]]) { + blossomData.inBlossom[blossomData.base[x]] = blossomData.inBlossom[blossomData.base[blossomData.match[x]]] = true; // Mark blossom vertices } - for (int x = v; base[x] != lca; x = parent[match[x]]) { - inBlossom[base[x]] = inBlossom[base[match[x]]] = true; // Mark blossom vertices + for (int x = blossomData.v; blossomData.base[x] != blossomData.lca; x = blossomData.parent[blossomData.match[x]]) { + blossomData.inBlossom[blossomData.base[x]] = blossomData.inBlossom[blossomData.base[blossomData.match[x]]] = true; // Mark blossom vertices } // Update the base for all marked vertices - for (int i = 0; i < base.length; i++) { - if (inBlossom[base[i]]) { - base[i] = lca; // Contract to the lowest common ancestor - if (!inQueue[i]) { - queue.add(i); // Add to queue if not already present - inQueue[i] = true; + for (int i = 0; i < blossomData.base.length; i++) { + if (blossomData.inBlossom[blossomData.base[i]]) { + blossomData.base[i] = blossomData.lca; // Contract to the lowest common ancestor + if (!blossomData.inQueue[i]) { + blossomData.queue.add(i); // Add to queue if not already present + blossomData.inQueue[i] = true; } } } @@ -242,21 +235,48 @@ public static void runTests() { // Test Case 1: Simple triangle List edges1 = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 0}); int vertexCount1 = 3; - printMatchingResult("Test Case 1", maximumMatching(edges1, vertexCount1)); + printMatchingResult("Test Case 1", new EdmondsBlossomAlgorithm().maximumMatching(edges1, vertexCount1)); // Test Case 2: Square shape List edges2 = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 3}, new int[] {3, 0}); int vertexCount2 = 4; - printMatchingResult("Test Case 2", maximumMatching(edges2, vertexCount2)); + printMatchingResult("Test Case 2", new EdmondsBlossomAlgorithm().maximumMatching(edges2, vertexCount2)); // Test Case 3: Bipartite graph List edges3 = Arrays.asList(new int[] {0, 2}, new int[] {0, 3}, new int[] {1, 2}, new int[] {1, 3}); int vertexCount3 = 4; - printMatchingResult("Test Case 3", maximumMatching(edges3, vertexCount3)); + printMatchingResult("Test Case 3", new EdmondsBlossomAlgorithm().maximumMatching(edges3, vertexCount3)); // Test Case 4: More edges than vertices List edges4 = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {0, 2}, new int[] {1, 3}, new int[] {2, 3}); int vertexCount4 = 4; - printMatchingResult("Test Case 4", maximumMatching(edges4, vertexCount4)); + printMatchingResult("Test Case 4", new EdmondsBlossomAlgorithm().maximumMatching(edges4, vertexCount4)); } + + static class BlossomData { + Queue queue; + int[] parent; + int[] base; + boolean[] inBlossom; + int[] match; + boolean[] inQueue; + int u; + int v; + int lca; + + public BlossomData(Queue queue, int[] parent, int[] base, + boolean[] inBlossom, int[] match, boolean[] inQueue, + int u, int v, int lca) { + this.queue = queue; + this.parent = parent; + this.base = base; + this.inBlossom = inBlossom; + this.match = match; + this.inQueue = inQueue; + this.u = u; + this.v = v; + this.lca = lca; + } + } + } From 11722aca942a91fa47afebc1d73d57b01b7b0949 Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Wed, 25 Sep 2024 01:08:49 +0530 Subject: [PATCH 12/28] Fix CheckStyle issues --- .../graphs/EdmondsBlossomAlgorithm.java | 138 +++++++++--------- 1 file changed, 67 insertions(+), 71 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java index ad50f7538627..8c68295fccaf 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java @@ -2,8 +2,8 @@ import java.util.ArrayList; import java.util.Arrays; -import java.util.List; import java.util.LinkedList; +import java.util.List; import java.util.Queue; /** @@ -11,24 +11,6 @@ * to find the maximum matching in a general graph. The algorithm efficiently * handles cases where the graph contains odd-length cycles by contracting * "blossoms" and finding augmenting paths. - *

- * The maximum matching problem seeks to find the largest set of vertex pairs - * such that no vertex is part of more than one pair, which is especially useful - * in graph theory problems like job assignments, scheduling, and network flows. - *

- * This implementation supports the following features: - * - Handling general graphs (not restricted to bipartite graphs). - * - Finding augmenting paths using BFS. - * - Contracting blossoms to overcome odd-length cycles. - * - Returning the list of matched vertex pairs. - *

- * Example: - * For a triangle graph with edges {(0, 1), (1, 2), (2, 0)}, the algorithm - * would find a maximum matching like {(0, 1)}, where vertex 2 is unmatched. - *

- * This class includes test cases in the main method to demonstrate how - * the algorithm works on different graph structures, such as simple triangles, - * squares, bipartite graphs, and graphs with more edges than vertices. */ public final class EdmondsBlossomAlgorithm { @@ -36,7 +18,7 @@ private EdmondsBlossomAlgorithm() { // Prevent instantiation of the utility class } - private static final int UNMATCHED = -1; + private static final int UNMATCHED = -1; // Constant to represent unmatched vertices /** * Finds the maximum matching in a general graph (Edmonds Blossom Algorithm). @@ -119,7 +101,7 @@ public List maximumMatching(List edges, int vertexCount) { // Case 3: Both x and y have a parent; check for a cycle/blossom int baseU = findBase(base, parent, current, y); if (baseU != UNMATCHED) { - contractBlossom(new BlossomData(queue, parent, base, inBlossom, match, inQueue, current, y, baseU)); + contractBlossom(new BlossomData(new BlossomAuxData(queue, parent, base, inBlossom, match, inQueue), current, y, baseU)); } } } @@ -195,20 +177,25 @@ private static int findBase(int[] base, int[] parent, int u, int v) { * @param blossomData The data containing the parameters related to the blossom contraction. */ private static void contractBlossom(BlossomData blossomData) { - for (int x = blossomData.u; blossomData.base[x] != blossomData.lca; x = blossomData.parent[blossomData.match[x]]) { - blossomData.inBlossom[blossomData.base[x]] = blossomData.inBlossom[blossomData.base[blossomData.match[x]]] = true; // Mark blossom vertices + // Mark vertices involved in the blossom + for (int x = blossomData.u; blossomData.auxData.base[x] != blossomData.lca; + x = blossomData.auxData.parent[blossomData.auxData.match[x]]) { + blossomData.auxData.inBlossom[blossomData.auxData.base[x]] = + blossomData.auxData.inBlossom[blossomData.auxData.base[blossomData.auxData.match[x]]] = true; // Mark blossom vertices } - for (int x = blossomData.v; blossomData.base[x] != blossomData.lca; x = blossomData.parent[blossomData.match[x]]) { - blossomData.inBlossom[blossomData.base[x]] = blossomData.inBlossom[blossomData.base[blossomData.match[x]]] = true; // Mark blossom vertices + for (int x = blossomData.v; blossomData.auxData.base[x] != blossomData.lca; + x = blossomData.auxData.parent[blossomData.auxData.match[x]]) { + blossomData.auxData.inBlossom[blossomData.auxData.base[x]] = + blossomData.auxData.inBlossom[blossomData.auxData.base[blossomData.auxData.match[x]]] = true; // Mark blossom vertices } // Update the base for all marked vertices - for (int i = 0; i < blossomData.base.length; i++) { - if (blossomData.inBlossom[blossomData.base[i]]) { - blossomData.base[i] = blossomData.lca; // Contract to the lowest common ancestor - if (!blossomData.inQueue[i]) { - blossomData.queue.add(i); // Add to queue if not already present - blossomData.inQueue[i] = true; + for (int i = 0; i < blossomData.auxData.base.length; i++) { + if (blossomData.auxData.inBlossom[blossomData.auxData.base[i]]) { + blossomData.auxData.base[i] = blossomData.lca; // Contract to the lowest common ancestor + if (!blossomData.auxData.inQueue[i]) { + blossomData.auxData.queue.add(i); // Add to queue if not already present + blossomData.auxData.inQueue[i] = true; } } } @@ -221,62 +208,71 @@ private static void contractBlossom(BlossomData blossomData) { * @param matching The list of matched pairs of vertices. */ private static void printMatchingResult(String testCase, List matching) { - System.out.print(testCase + ": "); - for (int[] match : matching) { - System.out.print(Arrays.toString(match) + " "); + System.out.print(testCase + " Matching: "); + for (int[] pair : matching) { + System.out.print("(" + pair[0] + ", " + pair[1] + ") "); } System.out.println(); } /** - * Runs test cases to demonstrate the functionality of the algorithm. + * Auxiliary data class to encapsulate common parameters for the blossom operations. */ - public static void runTests() { - // Test Case 1: Simple triangle - List edges1 = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 0}); - int vertexCount1 = 3; - printMatchingResult("Test Case 1", new EdmondsBlossomAlgorithm().maximumMatching(edges1, vertexCount1)); - - // Test Case 2: Square shape - List edges2 = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 3}, new int[] {3, 0}); - int vertexCount2 = 4; - printMatchingResult("Test Case 2", new EdmondsBlossomAlgorithm().maximumMatching(edges2, vertexCount2)); - - // Test Case 3: Bipartite graph - List edges3 = Arrays.asList(new int[] {0, 2}, new int[] {0, 3}, new int[] {1, 2}, new int[] {1, 3}); - int vertexCount3 = 4; - printMatchingResult("Test Case 3", new EdmondsBlossomAlgorithm().maximumMatching(edges3, vertexCount3)); - - // Test Case 4: More edges than vertices - List edges4 = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {0, 2}, new int[] {1, 3}, new int[] {2, 3}); - int vertexCount4 = 4; - printMatchingResult("Test Case 4", new EdmondsBlossomAlgorithm().maximumMatching(edges4, vertexCount4)); - } + static class BlossomAuxData { + Queue queue; // Queue for BFS traversal + int[] parent; // Parent array to store the paths + int[] base; // Base array to track the base of each vertex + boolean[] inBlossom; // Flags to indicate if a vertex is in a blossom + int[] match; // Array to store matches for each vertex + boolean[] inQueue; // Flags to track vertices in the BFS queue - static class BlossomData { - Queue queue; - int[] parent; - int[] base; - boolean[] inBlossom; - int[] match; - boolean[] inQueue; - int u; - int v; - int lca; - - public BlossomData(Queue queue, int[] parent, int[] base, - boolean[] inBlossom, int[] match, boolean[] inQueue, - int u, int v, int lca) { + BlossomAuxData(Queue queue, int[] parent, int[] base, boolean[] inBlossom, + int[] match, boolean[] inQueue) { this.queue = queue; this.parent = parent; this.base = base; this.inBlossom = inBlossom; this.match = match; this.inQueue = inQueue; + } + } + + /** + * BlossomData class with reduced parameters. + */ + static class BlossomData { + BlossomAuxData auxData; // Use the auxiliary data class + int u; // One vertex in the edge + int v; // Another vertex in the edge + int lca; // Lowest Common Ancestor + + BlossomData(BlossomAuxData auxData, int u, int v, int lca) { + this.auxData = auxData; this.u = u; this.v = v; this.lca = lca; } } -} + /** + * Method to run multiple test cases for the algorithm. + */ + private static void runTests() { + // Define test cases + List edges1 = Arrays.asList(new int[]{0, 1}, new int[]{1, 2}, new int[]{2, 0}); + List edges2 = Arrays.asList(new int[]{0, 1}, new int[]{1, 2}, new int[]{3, 4}); + List edges3 = Arrays.asList(new int[]{0, 1}, new int[]{1, 2}, new int[]{2, 3}, new int[]{3, 0}, new int[]{4, 5}); + + // Create an instance of the algorithm + EdmondsBlossomAlgorithm algorithm = new EdmondsBlossomAlgorithm(); + + // Run the test cases + List> testCases = Arrays.asList(edges1, edges2, edges3); + int vertexCount = 6; // Adjust based on the number of vertices in the test cases + + for (int i = 0; i < testCases.size(); i++) { + List matching = algorithm.maximumMatching(testCases.get(i), vertexCount); + printMatchingResult("Test Case " + (i + 1), matching); + } + } +} \ No newline at end of file From 893aabf92d2e88bbc8f544ef3ec5a758a25df60d Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Wed, 25 Sep 2024 01:14:19 +0530 Subject: [PATCH 13/28] Fixed Clang --- .../graphs/EdmondsBlossomAlgorithm.java | 21 +++++++------------ 1 file changed, 8 insertions(+), 13 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java index 8c68295fccaf..c8a4da223e38 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java @@ -178,15 +178,11 @@ private static int findBase(int[] base, int[] parent, int u, int v) { */ private static void contractBlossom(BlossomData blossomData) { // Mark vertices involved in the blossom - for (int x = blossomData.u; blossomData.auxData.base[x] != blossomData.lca; - x = blossomData.auxData.parent[blossomData.auxData.match[x]]) { - blossomData.auxData.inBlossom[blossomData.auxData.base[x]] = - blossomData.auxData.inBlossom[blossomData.auxData.base[blossomData.auxData.match[x]]] = true; // Mark blossom vertices + for (int x = blossomData.u; blossomData.auxData.base[x] != blossomData.lca; x = blossomData.auxData.parent[blossomData.auxData.match[x]]) { + blossomData.auxData.inBlossom[blossomData.auxData.base[x]] = blossomData.auxData.inBlossom[blossomData.auxData.base[blossomData.auxData.match[x]]] = true; // Mark blossom vertices } - for (int x = blossomData.v; blossomData.auxData.base[x] != blossomData.lca; - x = blossomData.auxData.parent[blossomData.auxData.match[x]]) { - blossomData.auxData.inBlossom[blossomData.auxData.base[x]] = - blossomData.auxData.inBlossom[blossomData.auxData.base[blossomData.auxData.match[x]]] = true; // Mark blossom vertices + for (int x = blossomData.v; blossomData.auxData.base[x] != blossomData.lca; x = blossomData.auxData.parent[blossomData.auxData.match[x]]) { + blossomData.auxData.inBlossom[blossomData.auxData.base[x]] = blossomData.auxData.inBlossom[blossomData.auxData.base[blossomData.auxData.match[x]]] = true; // Mark blossom vertices } // Update the base for all marked vertices @@ -226,8 +222,7 @@ static class BlossomAuxData { int[] match; // Array to store matches for each vertex boolean[] inQueue; // Flags to track vertices in the BFS queue - BlossomAuxData(Queue queue, int[] parent, int[] base, boolean[] inBlossom, - int[] match, boolean[] inQueue) { + BlossomAuxData(Queue queue, int[] parent, int[] base, boolean[] inBlossom, int[] match, boolean[] inQueue) { this.queue = queue; this.parent = parent; this.base = base; @@ -259,9 +254,9 @@ static class BlossomData { */ private static void runTests() { // Define test cases - List edges1 = Arrays.asList(new int[]{0, 1}, new int[]{1, 2}, new int[]{2, 0}); - List edges2 = Arrays.asList(new int[]{0, 1}, new int[]{1, 2}, new int[]{3, 4}); - List edges3 = Arrays.asList(new int[]{0, 1}, new int[]{1, 2}, new int[]{2, 3}, new int[]{3, 0}, new int[]{4, 5}); + List edges1 = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 0}); + List edges2 = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {3, 4}); + List edges3 = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 3}, new int[] {3, 0}, new int[] {4, 5}); // Create an instance of the algorithm EdmondsBlossomAlgorithm algorithm = new EdmondsBlossomAlgorithm(); From cb6de459c7b4cbf4c375e06a7a6b51121bdb19de Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Wed, 25 Sep 2024 01:16:36 +0530 Subject: [PATCH 14/28] Fixed Clang --- .../datastructures/graphs/EdmondsBlossomAlgorithm.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java index c8a4da223e38..6b3408b229c1 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java @@ -270,4 +270,4 @@ private static void runTests() { printMatchingResult("Test Case " + (i + 1), matching); } } -} \ No newline at end of file +} From b8a9f213955fbaa6197d5d9974035edbd6cb644d Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Wed, 25 Sep 2024 01:22:38 +0530 Subject: [PATCH 15/28] Fixed checkStyle --- .../graphs/EdmondsBlossomAlgorithm.java | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java index 6b3408b229c1..728331209e20 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java @@ -150,24 +150,24 @@ private static int findBase(int[] base, int[] parent, int u, int v) { boolean[] visited = new boolean[base.length]; // Mark ancestors of u - int currentU = u; // Use a temporary variable + int currentU = u; while (true) { - currentU = base[currentU]; // Assign to the temporary variable - visited[currentU] = true; // Mark as visited + currentU = base[currentU]; // Move assignment out of the condition + visited[currentU] = true; if (parent[currentU] == UNMATCHED) { break; } - currentU = parent[currentU]; // Reassign to the temporary variable + currentU = parent[currentU]; // Move assignment out of the condition } // Find the common ancestor of v - int currentV = v; // Use a temporary variable + int currentV = v; while (true) { - currentV = base[currentV]; // Assign to the temporary variable + currentV = base[currentV]; // Move assignment out of the condition if (visited[currentV]) { - return currentV; // The first visited node is the lowest common ancestor + return currentV; } - currentV = parent[currentV]; // Reassign to the temporary variable + currentV = parent[currentV]; // Move assignment out of the condition } } From 739ae10b4c52d6e86e96b4d79f404683cc338089 Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Wed, 25 Sep 2024 01:45:19 +0530 Subject: [PATCH 16/28] Fixed checkStyle --- .../graphs/EdmondsBlossomAlgorithm.java | 22 ++++++++++++++----- 1 file changed, 17 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java index 728331209e20..215833e886de 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java @@ -177,20 +177,32 @@ private static int findBase(int[] base, int[] parent, int u, int v) { * @param blossomData The data containing the parameters related to the blossom contraction. */ private static void contractBlossom(BlossomData blossomData) { - // Mark vertices involved in the blossom + // Contract vertices for u and mark them as part of the blossom for (int x = blossomData.u; blossomData.auxData.base[x] != blossomData.lca; x = blossomData.auxData.parent[blossomData.auxData.match[x]]) { - blossomData.auxData.inBlossom[blossomData.auxData.base[x]] = blossomData.auxData.inBlossom[blossomData.auxData.base[blossomData.auxData.match[x]]] = true; // Mark blossom vertices + int baseX = blossomData.auxData.base[x]; // Extract base[x] to a local variable + int matchBaseX = blossomData.auxData.base[blossomData.auxData.match[x]]; // Extract base[match[x]] to a local variable + + // Mark blossom vertices + blossomData.auxData.inBlossom[baseX] = blossomData.auxData.inBlossom[matchBaseX] = true; } + + // Contract vertices for v and mark them as part of the blossom for (int x = blossomData.v; blossomData.auxData.base[x] != blossomData.lca; x = blossomData.auxData.parent[blossomData.auxData.match[x]]) { - blossomData.auxData.inBlossom[blossomData.auxData.base[x]] = blossomData.auxData.inBlossom[blossomData.auxData.base[blossomData.auxData.match[x]]] = true; // Mark blossom vertices + int baseX = blossomData.auxData.base[x]; // Extract base[x] to a local variable + int matchBaseX = blossomData.auxData.base[blossomData.auxData.match[x]]; // Extract base[match[x]] to a local variable + + // Mark blossom vertices + blossomData.auxData.inBlossom[baseX] = blossomData.auxData.inBlossom[matchBaseX] = true; } // Update the base for all marked vertices for (int i = 0; i < blossomData.auxData.base.length; i++) { if (blossomData.auxData.inBlossom[blossomData.auxData.base[i]]) { - blossomData.auxData.base[i] = blossomData.lca; // Contract to the lowest common ancestor + blossomData.auxData.base[i] = blossomData.lca; // Contract to the lowest common ancestor (LCA) + + // Add to the queue if not already present if (!blossomData.auxData.inQueue[i]) { - blossomData.auxData.queue.add(i); // Add to queue if not already present + blossomData.auxData.queue.add(i); blossomData.auxData.inQueue[i] = true; } } From ea76d8c4d0882bbb72f017beec759cb0a58e1d18 Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Wed, 25 Sep 2024 01:55:15 +0530 Subject: [PATCH 17/28] Fixed checkStyle --- .../graphs/EdmondsBlossomAlgorithm.java | 26 +++++++++---------- 1 file changed, 12 insertions(+), 14 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java index 215833e886de..42381b008e6c 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java @@ -177,32 +177,30 @@ private static int findBase(int[] base, int[] parent, int u, int v) { * @param blossomData The data containing the parameters related to the blossom contraction. */ private static void contractBlossom(BlossomData blossomData) { - // Contract vertices for u and mark them as part of the blossom for (int x = blossomData.u; blossomData.auxData.base[x] != blossomData.lca; x = blossomData.auxData.parent[blossomData.auxData.match[x]]) { - int baseX = blossomData.auxData.base[x]; // Extract base[x] to a local variable - int matchBaseX = blossomData.auxData.base[blossomData.auxData.match[x]]; // Extract base[match[x]] to a local variable + int baseX = blossomData.auxData.base[x]; + int matchBaseX = blossomData.auxData.base[blossomData.auxData.match[x]]; - // Mark blossom vertices - blossomData.auxData.inBlossom[baseX] = blossomData.auxData.inBlossom[matchBaseX] = true; + // Split the inner assignment into two separate assignments + blossomData.auxData.inBlossom[baseX] = true; + blossomData.auxData.inBlossom[matchBaseX] = true; } - // Contract vertices for v and mark them as part of the blossom for (int x = blossomData.v; blossomData.auxData.base[x] != blossomData.lca; x = blossomData.auxData.parent[blossomData.auxData.match[x]]) { - int baseX = blossomData.auxData.base[x]; // Extract base[x] to a local variable - int matchBaseX = blossomData.auxData.base[blossomData.auxData.match[x]]; // Extract base[match[x]] to a local variable + int baseX = blossomData.auxData.base[x]; + int matchBaseX = blossomData.auxData.base[blossomData.auxData.match[x]]; - // Mark blossom vertices - blossomData.auxData.inBlossom[baseX] = blossomData.auxData.inBlossom[matchBaseX] = true; + // Split the inner assignment into two separate assignments + blossomData.auxData.inBlossom[baseX] = true; + blossomData.auxData.inBlossom[matchBaseX] = true; } // Update the base for all marked vertices for (int i = 0; i < blossomData.auxData.base.length; i++) { if (blossomData.auxData.inBlossom[blossomData.auxData.base[i]]) { - blossomData.auxData.base[i] = blossomData.lca; // Contract to the lowest common ancestor (LCA) - - // Add to the queue if not already present + blossomData.auxData.base[i] = blossomData.lca; // Contract to the lowest common ancestor if (!blossomData.auxData.inQueue[i]) { - blossomData.auxData.queue.add(i); + blossomData.auxData.queue.add(i); // Add to queue if not already present blossomData.auxData.inQueue[i] = true; } } From 1a0aa7d48de28c3032e4a1aa015eeb1d683a4940 Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Wed, 25 Sep 2024 02:01:59 +0530 Subject: [PATCH 18/28] Fixed bug --- .../graphs/EdmondsBlossomAlgorithm.java | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java index 42381b008e6c..5c64ca024944 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java @@ -28,18 +28,19 @@ private EdmondsBlossomAlgorithm() { * @return A list of matched pairs of vertices. */ public List maximumMatching(List edges, int vertexCount) { - // Create adjacency list to represent the graph - List[] graph = new ArrayList[vertexCount]; + List> graph = new ArrayList<>(vertexCount); + + // Initialize each vertex's adjacency list. for (int i = 0; i < vertexCount; i++) { - graph[i] = new ArrayList<>(); + graph.add(new ArrayList<>()); } // Populate the graph with the edges for (int[] edge : edges) { int u = edge[0]; int v = edge[1]; - graph[u].add(v); - graph[v].add(u); + graph.get(u).add(v); + graph.get(v).add(u); } // Initial matching array and auxiliary data structures @@ -70,7 +71,7 @@ public List maximumMatching(List edges, int vertexCount) { // BFS to find augmenting paths while (!queue.isEmpty() && !augmentingPathFound) { int current = queue.poll(); // Use a different name for clarity - for (int y : graph[current]) { + for (int y : graph.get(current)) { // Skip if we are looking at the same edge as the current match if (match[current] == y) { continue; From 02bdf1132b8879cf21acfde6eed443636a6d0b64 Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Wed, 25 Sep 2024 02:05:51 +0530 Subject: [PATCH 19/28] Fixed bug --- .../datastructures/graphs/EdmondsBlossomAlgorithm.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java index 5c64ca024944..c2e15e821499 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java @@ -263,7 +263,7 @@ static class BlossomData { /** * Method to run multiple test cases for the algorithm. */ - private static void runTests() { + public static void runTests() { // Define test cases List edges1 = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 0}); List edges2 = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {3, 4}); From 63a0b6fc0f96560096878b59236736c88543da31 Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Wed, 25 Sep 2024 20:51:27 +0530 Subject: [PATCH 20/28] Added Test Class with some tests --- .../graphs/EdmondsBlossomAlgorithm.java | 5 +- .../graphs/EdmondsBlossomAlgorithmTest.java | 116 ++++++++++++++++++ 2 files changed, 118 insertions(+), 3 deletions(-) create mode 100644 src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java index c2e15e821499..0e87cb86d957 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java @@ -12,10 +12,9 @@ * handles cases where the graph contains odd-length cycles by contracting * "blossoms" and finding augmenting paths. */ -public final class EdmondsBlossomAlgorithm { +public class EdmondsBlossomAlgorithm { private EdmondsBlossomAlgorithm() { - // Prevent instantiation of the utility class } private static final int UNMATCHED = -1; // Constant to represent unmatched vertices @@ -27,7 +26,7 @@ private EdmondsBlossomAlgorithm() { * @param vertexCount The number of vertices in the graph. * @return A list of matched pairs of vertices. */ - public List maximumMatching(List edges, int vertexCount) { + public static List maximumMatching(List edges, int vertexCount) { List> graph = new ArrayList<>(vertexCount); // Initialize each vertex's adjacency list. diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java new file mode 100644 index 000000000000..1319e063f4c8 --- /dev/null +++ b/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java @@ -0,0 +1,116 @@ +package com.thealgorithms.datastructures.graphs; + +import static org.junit.jupiter.api.Assertions.*; + +import java.util.Arrays; +import java.util.List; +import org.junit.jupiter.api.Test; + +/** + * Unit tests for the EdmondsBlossomAlgorithm class. + * + * These tests ensure that the Edmonds' Blossom Algorithm implementation + * works as expected for various graph structures, returning the correct + * maximum matching. + */ +public class EdmondsBlossomAlgorithmTest { + + /** + * Helper method to convert a list of matching pairs into a sorted 2D array. + * Sorting ensures consistent ordering of pairs and vertices for easier comparison in tests. + * + * @param matching List of matched pairs returned by the algorithm. + * @return A sorted 2D array of matching pairs. + */ + private int[][] convertMatchingToArray(List matching) { + // Convert the list of pairs into an array + int[][] result = matching.toArray(new int[0][]); + + // Sort each individual pair for consistency + for (int[] pair : result) { + Arrays.sort(pair); + } + + // Sort the array of pairs to ensure consistent order + Arrays.sort(result, (a, b) -> Integer.compare(a[0], b[0])); + return result; + } + + /** + * Test Case 1: A triangle graph where vertices 0, 1, and 2 form a cycle. + * The expected maximum matching is a single pair (0, 1) or any equivalent pair from the cycle. + */ + @Test + public void testCase1() { + List edges = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 0}); + List matching = EdmondsBlossomAlgorithm.maximumMatching(edges, 3); + + int[][] expected = new int[][] {{0, 1}}; + assertArrayEquals(expected, convertMatchingToArray(matching)); + } + + /** + * Test Case 2: A disconnected graph where vertices 0, 1, 2 form one component, + * and vertices 3, 4 form another. The expected maximum matching is two pairs: + * (0, 1) and (3, 4). + */ + @Test + public void testCase2() { + List edges = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {3, 4}); + List matching = EdmondsBlossomAlgorithm.maximumMatching(edges, 5); + + int[][] expected = new int[][] {{0, 1}, {3, 4}}; + assertArrayEquals(expected, convertMatchingToArray(matching)); + } + + /** + * Test Case 3: A cycle graph involving vertices 0, 1, 2, 3 forming a cycle, + * with an additional edge (4, 5) outside the cycle. + * The expected maximum matching is (0, 1) and (4, 5). + */ + @Test + public void testCase3() { + List edges = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 3}, new int[] {3, 0}, new int[] {4, 5}); + List matching = EdmondsBlossomAlgorithm.maximumMatching(edges, 6); + + // Updated expected output to include the maximum matching pairs + int[][] expected = new int[][] {{0, 1}, {2, 3}, {4, 5}}; + assertArrayEquals(expected, convertMatchingToArray(matching)); + } + + /** + * Test Case 4: A graph with no edges. + * Since there are no edges, the expected matching is an empty set. + */ + @Test + public void testCase4_noMatching() { + List edges = Arrays.asList(); // No edges + List matching = EdmondsBlossomAlgorithm.maximumMatching(edges, 3); + + int[][] expected = new int[][] {}; // No pairs expected + assertArrayEquals(expected, convertMatchingToArray(matching)); + } + + /** + * Test Case 5: A more complex graph with multiple cycles and extra edges. + * This tests the algorithm's ability to handle larger, more intricate graphs. + * The expected matching is {{0, 1}, {2, 5}, {3, 4}}. + */ + @Test + public void testCase5_largeGraph() { + List edges = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 3}, new int[] {3, 4}, new int[] {4, 5}, new int[] {5, 0}, new int[] {1, 4}, new int[] {2, 5}); + List matching = EdmondsBlossomAlgorithm.maximumMatching(edges, 6); + + // Check if the size of the matching is correct (i.e., 3 pairs) + assertEquals(3, matching.size()); + + // Check that the result contains valid pairs (any order is fine) + // Valid maximum matchings could be {{0, 1}, {2, 5}, {3, 4}} or {{0, 1}, {2, 3}, {4, 5}}, etc. + int[][] possibleMatching1 = new int[][] {{0, 1}, {2, 5}, {3, 4}}; + int[][] possibleMatching2 = new int[][] {{0, 1}, {2, 3}, {4, 5}}; + int[][] result = convertMatchingToArray(matching); + + // Assert that the result is one of the valid maximum matchings + assertTrue(Arrays.deepEquals(result, possibleMatching1) || Arrays.deepEquals(result, possibleMatching2)); + } +} From 6aae9b6a633daa73b0f07b3d7a61feeaa3754565 Mon Sep 17 00:00:00 2001 From: TarunVishwakarma1 Date: Wed, 25 Sep 2024 15:21:51 +0000 Subject: [PATCH 21/28] Update directory --- DIRECTORY.md | 1 + 1 file changed, 1 insertion(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index 08f91cbd7ff8..6e10721a4a93 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -659,6 +659,7 @@ * graphs * [BoruvkaAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/BoruvkaAlgorithmTest.java) * [DijkstraAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/DijkstraAlgorithmTest.java) + * [EdmondsBlossomAlgorithmTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java) * [FordFulkersonTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/FordFulkersonTest.java) * [HamiltonianCycleTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/HamiltonianCycleTest.java) * [KosarajuTest](https://github.com/TheAlgorithms/Java/blob/master/src/test/java/com/thealgorithms/datastructures/graphs/KosarajuTest.java) From 59c3e482d09b80da4d782e9583a6a4aebeefa990 Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Wed, 25 Sep 2024 20:54:33 +0530 Subject: [PATCH 22/28] Removed Class instantiation from runTests() method --- .../datastructures/graphs/EdmondsBlossomAlgorithm.java | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java index 0e87cb86d957..30eeb5034b74 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java @@ -269,14 +269,13 @@ public static void runTests() { List edges3 = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 3}, new int[] {3, 0}, new int[] {4, 5}); // Create an instance of the algorithm - EdmondsBlossomAlgorithm algorithm = new EdmondsBlossomAlgorithm(); // Run the test cases List> testCases = Arrays.asList(edges1, edges2, edges3); int vertexCount = 6; // Adjust based on the number of vertices in the test cases for (int i = 0; i < testCases.size(); i++) { - List matching = algorithm.maximumMatching(testCases.get(i), vertexCount); + List matching = EdmondsBlossomAlgorithm.maximumMatching(testCases.get(i), vertexCount); printMatchingResult("Test Case " + (i + 1), matching); } } From 899744625ea7bf659f469bc4cb9e210c95acedc6 Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Wed, 25 Sep 2024 21:02:54 +0530 Subject: [PATCH 23/28] added final to class name and destructured the imports of Test class --- .../datastructures/graphs/EdmondsBlossomAlgorithm.java | 2 +- .../graphs/EdmondsBlossomAlgorithmTest.java | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java index 30eeb5034b74..717732d5d1e1 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java @@ -12,7 +12,7 @@ * handles cases where the graph contains odd-length cycles by contracting * "blossoms" and finding augmenting paths. */ -public class EdmondsBlossomAlgorithm { +public final class EdmondsBlossomAlgorithm { private EdmondsBlossomAlgorithm() { } diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java index 1319e063f4c8..151c57570b9a 100644 --- a/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java +++ b/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java @@ -1,7 +1,8 @@ package com.thealgorithms.datastructures.graphs; -import static org.junit.jupiter.api.Assertions.*; - +import static org.junit.jupiter.api.Assertions.assertArrayEquals; +import static org.junit.jupiter.api.Assertions.assertEquals; +import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.Test; @@ -83,7 +84,7 @@ public void testCase3() { * Since there are no edges, the expected matching is an empty set. */ @Test - public void testCase4_noMatching() { + public void testCaseNoMatching() { List edges = Arrays.asList(); // No edges List matching = EdmondsBlossomAlgorithm.maximumMatching(edges, 3); @@ -97,7 +98,7 @@ public void testCase4_noMatching() { * The expected matching is {{0, 1}, {2, 5}, {3, 4}}. */ @Test - public void testCase5_largeGraph() { + public void testCaseLargeGraph() { List edges = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 3}, new int[] {3, 4}, new int[] {4, 5}, new int[] {5, 0}, new int[] {1, 4}, new int[] {2, 5}); List matching = EdmondsBlossomAlgorithm.maximumMatching(edges, 6); From 588d50f9ed83a60225580095a2d29d4be696e3fc Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Wed, 25 Sep 2024 21:08:30 +0530 Subject: [PATCH 24/28] clang format error --- .../datastructures/graphs/EdmondsBlossomAlgorithmTest.java | 1 + 1 file changed, 1 insertion(+) diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java index 151c57570b9a..600d96d1946a 100644 --- a/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java +++ b/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java @@ -3,6 +3,7 @@ import static org.junit.jupiter.api.Assertions.assertArrayEquals; import static org.junit.jupiter.api.Assertions.assertEquals; import static org.junit.jupiter.api.Assertions.assertTrue; + import java.util.Arrays; import java.util.List; import org.junit.jupiter.api.Test; From 529c1be814c9b1d1723d809e02384baa5df952e0 Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Wed, 25 Sep 2024 21:11:14 +0530 Subject: [PATCH 25/28] fixed bug in Test class --- .../datastructures/graphs/EdmondsBlossomAlgorithmTest.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java b/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java index 600d96d1946a..4a7232447e50 100644 --- a/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java +++ b/src/test/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithmTest.java @@ -5,6 +5,7 @@ import static org.junit.jupiter.api.Assertions.assertTrue; import java.util.Arrays; +import java.util.Collections; import java.util.List; import org.junit.jupiter.api.Test; @@ -86,7 +87,7 @@ public void testCase3() { */ @Test public void testCaseNoMatching() { - List edges = Arrays.asList(); // No edges + List edges = Collections.emptyList(); // No edges List matching = EdmondsBlossomAlgorithm.maximumMatching(edges, 3); int[][] expected = new int[][] {}; // No pairs expected From b61172794ec41d937b69682cc4f585da3db49721 Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Wed, 25 Sep 2024 21:25:09 +0530 Subject: [PATCH 26/28] Please this be last --- .../datastructures/graphs/EdmondsBlossomAlgorithm.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java index 717732d5d1e1..3c0458794ba1 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java @@ -275,7 +275,7 @@ public static void runTests() { int vertexCount = 6; // Adjust based on the number of vertices in the test cases for (int i = 0; i < testCases.size(); i++) { - List matching = EdmondsBlossomAlgorithm.maximumMatching(testCases.get(i), vertexCount); + List matching = maximumMatching(testCases.get(i), vertexCount); printMatchingResult("Test Case " + (i + 1), matching); } } From 14826e89702752770db87c262d198502f3bade40 Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Wed, 25 Sep 2024 21:44:52 +0530 Subject: [PATCH 27/28] Please Please This be last, Added Link to documentation --- .../datastructures/graphs/EdmondsBlossomAlgorithm.java | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java index 3c0458794ba1..0794b4d9662b 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java @@ -11,6 +11,10 @@ * to find the maximum matching in a general graph. The algorithm efficiently * handles cases where the graph contains odd-length cycles by contracting * "blossoms" and finding augmenting paths. + *

+ * Documentation of Algorithm (Stanford University) + *

+ * Wikipedia Documentation */ public final class EdmondsBlossomAlgorithm { From 8f5b4b008a19015bb0cbafd6acddc3452a80e1b4 Mon Sep 17 00:00:00 2001 From: Tarun Vishwakarma Date: Tue, 1 Oct 2024 19:11:56 +0530 Subject: [PATCH 28/28] Removed System.out and print matching result method --- .../graphs/EdmondsBlossomAlgorithm.java | 35 ------------------- 1 file changed, 35 deletions(-) diff --git a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java index 0794b4d9662b..27ad96d71876 100644 --- a/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java +++ b/src/main/java/com/thealgorithms/datastructures/graphs/EdmondsBlossomAlgorithm.java @@ -211,20 +211,6 @@ private static void contractBlossom(BlossomData blossomData) { } } - /** - * Helper method to print the matching results in a readable format. - * - * @param testCase The name of the test case being executed. - * @param matching The list of matched pairs of vertices. - */ - private static void printMatchingResult(String testCase, List matching) { - System.out.print(testCase + " Matching: "); - for (int[] pair : matching) { - System.out.print("(" + pair[0] + ", " + pair[1] + ") "); - } - System.out.println(); - } - /** * Auxiliary data class to encapsulate common parameters for the blossom operations. */ @@ -262,25 +248,4 @@ static class BlossomData { this.lca = lca; } } - - /** - * Method to run multiple test cases for the algorithm. - */ - public static void runTests() { - // Define test cases - List edges1 = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 0}); - List edges2 = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {3, 4}); - List edges3 = Arrays.asList(new int[] {0, 1}, new int[] {1, 2}, new int[] {2, 3}, new int[] {3, 0}, new int[] {4, 5}); - - // Create an instance of the algorithm - - // Run the test cases - List> testCases = Arrays.asList(edges1, edges2, edges3); - int vertexCount = 6; // Adjust based on the number of vertices in the test cases - - for (int i = 0; i < testCases.size(); i++) { - List matching = maximumMatching(testCases.get(i), vertexCount); - printMatchingResult("Test Case " + (i + 1), matching); - } - } }