private int[] distTo; // distTo[v] = number of edges on shortest path to v /** * Determines a maximum matching (and a minimum vertex cover) * in a bipartite graph. * * @param G the bipartite graph * @throws IllegalArgumentException if {@code G} is not bipartite */ public HopcroftKarp(Graph G) { bipartition = new BipartiteX(G); if (!bipartition.isBipartite()) { throw new IllegalArgumentException("graph is not bipartite"); } // initialize empty matching this.V = G.V(); mate = new int[V]; for (int v = 0; v < V; v++) mate[v] = UNMATCHED; // the call to hasAugmentingPath() provides enough info to reconstruct level graph while (hasAugmentingPath(G)) { // to be able to iterate over each adjacency list, keeping track of which // vertex in each adjacency list needs to be explored next Iterator<Integer>[] adj = (Iterator<Integer>[]) new Iterator[G.V()]; for (int v = 0; v < G.V(); v++) adj[v] = G.adj(v).iterator(); // for each unmatched vertex s on one side of bipartition for (int s = 0; s < V; s++) { if (isMatched(s) || !bipartition.color(s)) continue; // or use distTo[s] == 0 // find augmenting path from s using nonrecursive DFS Stack<Integer> path = new Stack<Integer>(); path.push(s); while (!path.isEmpty()) { int v = path.peek(); // retreat, no more edges in level graph leaving v if (!adj[v].hasNext()) path.pop(); // advance else { // process edge v-w only if it is an edge in level graph int w = adj[v].next(); if (!isLevelGraphEdge(v, w)) continue; // add w to augmenting path path.push(w); // augmenting path found: update the matching if (!isMatched(w)) { // StdOut.println("augmenting path: " + toString(path)); while (!path.isEmpty()) { int x = path.pop(); int y = path.pop(); mate[x] = y; mate[y] = x; } cardinality++; } } } } } // also find a min vertex cover inMinVertexCover = new boolean[V]; for (int v = 0; v < V; v++) { if (bipartition.color(v) && !marked[v]) inMinVertexCover[v] = true; if (!bipartition.color(v) && marked[v]) inMinVertexCover[v] = true; } assert certifySolution(G); }
// is the edge v-w a forward edge not in the matching or a reverse edge in the matching? private boolean isResidualGraphEdge(int v, int w) { if ((mate[v] != w) && bipartition.color(v)) return true; if ((mate[v] == w) && !bipartition.color(v)) return true; return false; }