mirror of
https://github.com/TheAlgorithms/Java.git
synced 2026-03-13 08:40:43 +08:00
Hopcroft karp Algorithm implementation and tests (#6465)
* Add Hopcroft-Karp algorithm and tests * Adding wikipedia url for Algorithm * fixing test issues * remove unused field flagged by PMD
This commit is contained in:
103
src/main/java/com/thealgorithms/graph/HopcroftKarp.java
Normal file
103
src/main/java/com/thealgorithms/graph/HopcroftKarp.java
Normal file
@@ -0,0 +1,103 @@
|
||||
package com.thealgorithms.graph;
|
||||
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.Queue;
|
||||
|
||||
/**
|
||||
* Hopcroft–Karp algorithm for maximum bipartite matching.
|
||||
*
|
||||
* Left part: vertices [0,nLeft-1], Right part: [0,nRight-1].
|
||||
* Adjacency list: for each left vertex u, list right vertices v it connects to.
|
||||
*
|
||||
* Time complexity: O(E * sqrt(V)).
|
||||
*
|
||||
* @see <a href="https://en.wikipedia.org/wiki/Hopcroft%E2%80%93Karp_algorithm">
|
||||
* Wikipedia: Hopcroft–Karp algorithm</a>
|
||||
* @author ptzecher
|
||||
*/
|
||||
public class HopcroftKarp {
|
||||
|
||||
private final int nLeft;
|
||||
private final List<List<Integer>> adj;
|
||||
|
||||
private final int[] pairU;
|
||||
private final int[] pairV;
|
||||
private final int[] dist;
|
||||
|
||||
public HopcroftKarp(int nLeft, int nRight, List<List<Integer>> adj) {
|
||||
this.nLeft = nLeft;
|
||||
this.adj = adj;
|
||||
|
||||
this.pairU = new int[nLeft];
|
||||
this.pairV = new int[nRight];
|
||||
this.dist = new int[nLeft];
|
||||
|
||||
Arrays.fill(pairU, -1);
|
||||
Arrays.fill(pairV, -1);
|
||||
}
|
||||
|
||||
/** Returns the size of the maximum matching. */
|
||||
public int maxMatching() {
|
||||
int matching = 0;
|
||||
while (bfs()) {
|
||||
for (int u = 0; u < nLeft; u++) {
|
||||
if (pairU[u] == -1 && dfs(u)) {
|
||||
matching++;
|
||||
}
|
||||
}
|
||||
}
|
||||
return matching;
|
||||
}
|
||||
|
||||
// BFS to build layers
|
||||
private boolean bfs() {
|
||||
Queue<Integer> queue = new ArrayDeque<>();
|
||||
Arrays.fill(dist, -1);
|
||||
|
||||
for (int u = 0; u < nLeft; u++) {
|
||||
if (pairU[u] == -1) {
|
||||
dist[u] = 0;
|
||||
queue.add(u);
|
||||
}
|
||||
}
|
||||
|
||||
boolean foundAugPath = false;
|
||||
while (!queue.isEmpty()) {
|
||||
int u = queue.poll();
|
||||
for (int v : adj.get(u)) {
|
||||
int matchedLeft = pairV[v];
|
||||
if (matchedLeft == -1) {
|
||||
foundAugPath = true;
|
||||
} else if (dist[matchedLeft] == -1) {
|
||||
dist[matchedLeft] = dist[u] + 1;
|
||||
queue.add(matchedLeft);
|
||||
}
|
||||
}
|
||||
}
|
||||
return foundAugPath;
|
||||
}
|
||||
|
||||
// DFS to find augmenting paths within the BFS layering
|
||||
private boolean dfs(int u) {
|
||||
for (int v : adj.get(u)) {
|
||||
int matchedLeft = pairV[v];
|
||||
if (matchedLeft == -1 || (dist[matchedLeft] == dist[u] + 1 && dfs(matchedLeft))) {
|
||||
pairU[u] = v;
|
||||
pairV[v] = u;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
dist[u] = -1;
|
||||
return false;
|
||||
}
|
||||
|
||||
public int[] getLeftMatches() {
|
||||
return pairU.clone();
|
||||
}
|
||||
|
||||
public int[] getRightMatches() {
|
||||
return pairV.clone();
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user