From 432a53ae75eeb8c9eb1eb88933a19a02a71814e7 Mon Sep 17 00:00:00 2001 From: Adam Soltan Date: Tue, 13 Jan 2026 20:43:42 +0100 Subject: [PATCH 1/2] Add new Hopcroft-Karp implementation --- content/graph/hopcroftKarp.h | 75 ++++++++++++------------------------ 1 file changed, 24 insertions(+), 51 deletions(-) diff --git a/content/graph/hopcroftKarp.h b/content/graph/hopcroftKarp.h index 83c9847a9..e9bf249f2 100644 --- a/content/graph/hopcroftKarp.h +++ b/content/graph/hopcroftKarp.h @@ -1,61 +1,34 @@ /** - * Author: Chen Xing - * Date: 2009-10-13 + * Author: Adam Soltan + * Date: 2026-01-13 * License: CC0 - * Source: N/A * Description: Fast bipartite matching algorithm. Graph $g$ should be a list - * of neighbors of the left partition, and $btoa$ should be a vector full of - * -1's of the same size as the right partition. Returns the size of - * the matching. $btoa[i]$ will be the match for vertex $i$ on the right side, + * of neighbors of the left partition, and $r$ should be a vector full of + * $-1$'s of the same size as the right partition. Returns the size of + * the matching. $r[i]$ will be the match for vertex $i$ on the right side, * or $-1$ if it's not matched. - * Usage: vi btoa(m, -1); hopcroftKarp(g, btoa); - * Time: O(\sqrt{V}E) - * Status: stress-tested by MinimumVertexCover, and tested on oldkattis.adkbipmatch and SPOJ:MATCHING + * Time: O(E \sqrt{V}) + * Status: stress-tested by MinimumVertexCover and tested on Library Checker */ #pragma once -bool dfs(int a, int L, vector& g, vi& btoa, vi& A, vi& B) { - if (A[a] != L) return 0; - A[a] = -1; - for (int b : g[a]) if (B[b] == L + 1) { - B[b] = 0; - if (btoa[b] == -1 || dfs(btoa[b], L + 1, g, btoa, A, B)) - return btoa[b] = a, 1; - } - return 0; -} - -int hopcroftKarp(vector& g, vi& btoa) { - int res = 0; - vi A(g.size()), B(btoa.size()), cur, next; - for (;;) { - fill(all(A), 0); - fill(all(B), 0); - /// Find the starting nodes for BFS (i.e. layer 0). - cur.clear(); - for (int a : btoa) if(a != -1) A[a] = -1; - rep(a,0,sz(g)) if(A[a] == 0) cur.push_back(a); - /// Find all layers using bfs. - for (int lay = 1;; lay++) { - bool islast = 0; - next.clear(); - for (int a : cur) for (int b : g[a]) { - if (btoa[b] == -1) { - B[b] = lay; - islast = 1; - } - else if (btoa[b] != a && !B[b]) { - B[b] = lay; - next.push_back(btoa[b]); - } - } - if (islast) break; - if (next.empty()) return res; - for (int a : next) A[a] = lay; - cur.swap(next); +int hopcroftKarp(vector& g, vi& r) { + int n = sz(g), res = 0; + vi l(n, -1), q(n), d(n); + auto dfs = [&](auto f, int u) -> bool { + int t = exchange(d[u], 0) + 1; + for (int v : g[u]) + if (r[v] == -1 || (d[r[v]] == t && f(f, r[v]))) + return l[u] = v, r[v] = u, 1; + return 0; + }; + for (int t = 0, f = 0;; t = f = 0, d.assign(n, 0)) { + rep(i, 0, n) if (l[i] == -1) q[t++] = i, d[i] = 1; + rep(i, 0, t) for (int v : g[q[i]]) { + if (r[v] == -1) f = 1; + else if (!d[r[v]]) d[r[v]] = d[q[i]] + 1, q[t++] = r[v]; } - /// Use DFS to scan for augmenting paths. - rep(a,0,sz(g)) - res += dfs(a, 0, g, btoa, A, B); + if (!f) return res; + rep(i, 0, n) if (l[i] == -1) res += dfs(dfs, i); } } From 2d09a5bc9cec377ad3654253fa69d50da4e8441f Mon Sep 17 00:00:00 2001 From: Simon Lindholm Date: Sun, 25 Jan 2026 11:57:35 +0100 Subject: [PATCH 2/2] Formatting --- content/graph/hopcroftKarp.h | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/graph/hopcroftKarp.h b/content/graph/hopcroftKarp.h index e9bf249f2..809cdc524 100644 --- a/content/graph/hopcroftKarp.h +++ b/content/graph/hopcroftKarp.h @@ -23,12 +23,12 @@ int hopcroftKarp(vector& g, vi& r) { return 0; }; for (int t = 0, f = 0;; t = f = 0, d.assign(n, 0)) { - rep(i, 0, n) if (l[i] == -1) q[t++] = i, d[i] = 1; - rep(i, 0, t) for (int v : g[q[i]]) { + rep(i,0,n) if (l[i] == -1) q[t++] = i, d[i] = 1; + rep(i,0,t) for (int v : g[q[i]]) { if (r[v] == -1) f = 1; else if (!d[r[v]]) d[r[v]] = d[q[i]] + 1, q[t++] = r[v]; } if (!f) return res; - rep(i, 0, n) if (l[i] == -1) res += dfs(dfs, i); + rep(i,0,n) if (l[i] == -1) res += dfs(dfs, i); } }