TOP > グラフ 二部グラフの最大マッチング 二部グラフの最大マッチング(Hopcroft-Karp) 2018/03/31 • ei1333 説明 二部グラフの最大マッチングを求める。 計算量 $O(E \sqrt V)$ 実装例 HopcroftKarp($n$, $m$):= 一方の頂点数を $n$, もう一方の頂点数を $m$ で初期化する。 add_edge($u$, $v$):= 頂点 $u, v$ 間に辺を張る。 bipartite_matching():= 二部グラフの最大マッチングを返す。 struct HopcroftKarp { vector< vector< int > > graph; vector< int > dist, match; vector< bool > used, vv; HopcroftKarp(int n, int m) : graph(n), match(m, -1), used(n) {} void add_edge(int u, int v) { graph[u].push_back(v); } void bfs() { dist.assign(graph.size(), -1); queue< int > que; for(int i = 0; i < graph.size(); i++) { if(!used[i]) { que.emplace(i); dist[i] = 0; } } while(!que.empty()) { int a = que.front(); que.pop(); for(auto &b : graph[a]) { int c = match[b]; if(c >= 0 && dist[c] == -1) { dist[c] = dist[a] + 1; que.emplace(c); } } } } bool dfs(int a) { vv[a] = true; for(auto &b : graph[a]) { int c = match[b]; if(c < 0 || (!vv[c] && dist[c] == dist[a] + 1 && dfs(c))) { match[b] = a; used[a] = true; return (true); } } return (false); } int bipartite_matching() { int ret = 0; while(true) { bfs(); vv.assign(graph.size(), false); int flow = 0; for(int i = 0; i < graph.size(); i++) { if(!used[i] && dfs(i)) ++flow; } if(flow == 0) return (ret); ret += flow; } } void output() { for(int i = 0; i < match.size(); i++) { if(~match[i]) { cout << match[i] << "-" << i << endl; } } } }; 検証 AOJ GRL_7_A 2部マッチング #define PROBLEM "http://judge.u-aizu.ac.jp/onlinejudge/description.jsp?id=GRL_7_A" #include "../../template/template.cpp" #include "../template.cpp" #include "../hopcroft-karp.cpp" int main() { int X, Y, E; scanf("%d %d %d", &X, &Y, &E); HopcroftKarp bm(X, Y); for(int i = 0; i < E; i++) { int a, b; scanf("%d %d", &a, &b); bm.add_edge(a, b); } printf("%d\n", bm.bipartite_matching()); }