Chapter 12. Bipartite Matching
Classical bipartite matching, vertex-cover, and chain-cover constructions.
This page: Classical forms. View LLP forms »
This page collects the classical / sequential implementations of the algorithms developed in this chapter. The lattice-linear (LLP) reformulations and chapter setup live on the LLP companion page.
BipartiteMatching
The classical sequential augmenting-path algorithm. tryMatch(u, ...)
tries to match the left vertex $u$ via a DFS over the right side; if it succeeds,
the path-toggling is folded into the recursion.
Time complexity: $O(n \cdot m)$ via the augmenting-path scheme, where $n$ is the number of left vertices and $m$ the number of edges.
int[] BipartiteMatching(int[][] adj) {
int n = adj.length;
int m = adj[0].length;
int[] G = new int[n];
int[] partner = new int[m];
int j = 0;
while (j < m) {
partner[j] = 0 - 1;
j = j + 1;
};
int u = 0;
while (u < n) {
boolean[] seen = new boolean[m];
if (tryMatch(u, adj, partner, seen)) {
G[u] = 1;
};
u = u + 1;
};
return G;
}
boolean tryMatch(int u, int[][] adj, int[] partner, boolean[] seen) {
int m = adj[0].length;
int v = 0;
while (v < m) {
if (adj[u][v] == 1 && !seen[v]) {
seen[v] = true;
if (partner[v] == 0 - 1 || tryMatch(partner[v], adj, partner, seen)) {
partner[v] = u;
return true;
}
};
v = v + 1;
};
return false;
}
ChainCoverFromMatching
Fulkerson's reduction in code: from a matching $M$ in the strict split of a poset, glue chains together by setting $C[u] := v$ for every matched pair $(u^-, v^+)$. Pointer-jumping then collapses each chain into a single root in $O(\log n)$ rounds.
Time complexity: $O(n)$ work, $O(\log n)$ parallel rounds via pointer-jumping.
int[] ParChainCoverFromMatching(int[] matchPartner) {
int n = matchPartner.length;
int[] C = new int[n];
int i = 0;
while (i < n) { C[i] = i; i = i + 1; };
int u = 0;
while (u < n) {
int v = matchPartner[u];
if (v != 0 - 1) {
C[u] = v;
};
u = u + 1;
};
parentPointerJumping(C);
return C;
}
void parentPointerJumping(int[] C) {
int n = C.length;
boolean changed = true;
while (changed) {
changed = false;
int i = 0;
while (i < n) {
int p = C[i];
if (C[p] != p) { C[i] = C[p]; changed = true; };
i = i + 1;
}
}
}
VertexCoverFromMatching
King's-theorem construction in code: build a vertex cover of size $|M|$ in two parallel passes over the edges. Pass 1 puts every $L$-endpoint of $M$ into the cover. Pass 2 sweeps every uncovered edge $(u, v)$ with $u, v \notin C$, swapping the cover mark from a matched neighbour onto the uncovered endpoint.
Time complexity: $O(n + m)$.
boolean[] ParVertexCoverFromMatching(int[][] adj, int[] matchL) {
int L = adj.length;
int R = adj[0].length;
boolean[] C = new boolean[L + R];
int[] partner = new int[L + R];
int i = 0;
while (i < L + R) {
partner[i] = 0 - 1;
i = i + 1;
};
int u = 0;
while (u < L) {
int v = matchL[u];
if (v != 0 - 1) {
C[u] = true;
partner[u] = L + v;
partner[L + v] = u;
};
u = u + 1;
};
u = 0;
while (u < L) {
int v = 0;
while (v < R) {
if (adj[u][v] == 1 && !C[u] && !C[L + v]) {
if (partner[u] != 0 - 1) {
C[partner[u]] = false;
C[u] = true;
} else {
C[partner[L + v]] = false;
C[L + v] = true;
}
};
v = v + 1;
};
u = u + 1;
};
return C;
}