Skip to content

Commit 662c8a9

Browse files
authored
Shorter and faster Hopcroft-Karp implementation (#308)
1 parent c1bfa26 commit 662c8a9

File tree

1 file changed

+24
-51
lines changed

1 file changed

+24
-51
lines changed

content/graph/hopcroftKarp.h

Lines changed: 24 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -1,61 +1,34 @@
11
/**
2-
* Author: Chen Xing
3-
* Date: 2009-10-13
2+
* Author: Adam Soltan
3+
* Date: 2026-01-13
44
* License: CC0
5-
* Source: N/A
65
* Description: Fast bipartite matching algorithm. Graph $g$ should be a list
7-
* of neighbors of the left partition, and $btoa$ should be a vector full of
8-
* -1's of the same size as the right partition. Returns the size of
9-
* the matching. $btoa[i]$ will be the match for vertex $i$ on the right side,
6+
* of neighbors of the left partition, and $r$ should be a vector full of
7+
* $-1$'s of the same size as the right partition. Returns the size of
8+
* the matching. $r[i]$ will be the match for vertex $i$ on the right side,
109
* or $-1$ if it's not matched.
11-
* Usage: vi btoa(m, -1); hopcroftKarp(g, btoa);
12-
* Time: O(\sqrt{V}E)
13-
* Status: stress-tested by MinimumVertexCover, and tested on oldkattis.adkbipmatch and SPOJ:MATCHING
10+
* Time: O(E \sqrt{V})
11+
* Status: stress-tested by MinimumVertexCover and tested on Library Checker
1412
*/
1513
#pragma once
1614

17-
bool dfs(int a, int L, vector<vi>& g, vi& btoa, vi& A, vi& B) {
18-
if (A[a] != L) return 0;
19-
A[a] = -1;
20-
for (int b : g[a]) if (B[b] == L + 1) {
21-
B[b] = 0;
22-
if (btoa[b] == -1 || dfs(btoa[b], L + 1, g, btoa, A, B))
23-
return btoa[b] = a, 1;
24-
}
25-
return 0;
26-
}
27-
28-
int hopcroftKarp(vector<vi>& g, vi& btoa) {
29-
int res = 0;
30-
vi A(g.size()), B(btoa.size()), cur, next;
31-
for (;;) {
32-
fill(all(A), 0);
33-
fill(all(B), 0);
34-
/// Find the starting nodes for BFS (i.e. layer 0).
35-
cur.clear();
36-
for (int a : btoa) if(a != -1) A[a] = -1;
37-
rep(a,0,sz(g)) if(A[a] == 0) cur.push_back(a);
38-
/// Find all layers using bfs.
39-
for (int lay = 1;; lay++) {
40-
bool islast = 0;
41-
next.clear();
42-
for (int a : cur) for (int b : g[a]) {
43-
if (btoa[b] == -1) {
44-
B[b] = lay;
45-
islast = 1;
46-
}
47-
else if (btoa[b] != a && !B[b]) {
48-
B[b] = lay;
49-
next.push_back(btoa[b]);
50-
}
51-
}
52-
if (islast) break;
53-
if (next.empty()) return res;
54-
for (int a : next) A[a] = lay;
55-
cur.swap(next);
15+
int hopcroftKarp(vector<vi>& g, vi& r) {
16+
int n = sz(g), res = 0;
17+
vi l(n, -1), q(n), d(n);
18+
auto dfs = [&](auto f, int u) -> bool {
19+
int t = exchange(d[u], 0) + 1;
20+
for (int v : g[u])
21+
if (r[v] == -1 || (d[r[v]] == t && f(f, r[v])))
22+
return l[u] = v, r[v] = u, 1;
23+
return 0;
24+
};
25+
for (int t = 0, f = 0;; t = f = 0, d.assign(n, 0)) {
26+
rep(i,0,n) if (l[i] == -1) q[t++] = i, d[i] = 1;
27+
rep(i,0,t) for (int v : g[q[i]]) {
28+
if (r[v] == -1) f = 1;
29+
else if (!d[r[v]]) d[r[v]] = d[q[i]] + 1, q[t++] = r[v];
5630
}
57-
/// Use DFS to scan for augmenting paths.
58-
rep(a,0,sz(g))
59-
res += dfs(a, 0, g, btoa, A, B);
31+
if (!f) return res;
32+
rep(i,0,n) if (l[i] == -1) res += dfs(dfs, i);
6033
}
6134
}

0 commit comments

Comments
 (0)