-
Notifications
You must be signed in to change notification settings - Fork 11
/
Copy pathbipartite_matching.hpp
99 lines (90 loc) · 3.02 KB
/
bipartite_matching.hpp
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
#pragma once
#include <cassert>
#include <iostream>
#include <vector>
// Bipartite matching of undirected bipartite graph (Hopcroft-Karp)
// https://ei1333.github.io/luzhiled/snippets/graph/hopcroft-karp.html
// Comprexity: O((V + E)sqrtV)
// int solve(): enumerate maximum number of matching / return -1 (if graph is not bipartite)
struct BipartiteMatching {
int V;
std::vector<std::vector<int>> to; // Adjacency list
std::vector<int> dist; // dist[i] = (Distance from i'th node)
std::vector<int> match; // match[i] = (Partner of i'th node) or -1 (No parter)
std::vector<int> used, vv;
std::vector<int> color; // color of each node(checking bipartition): 0/1/-1(not determined)
BipartiteMatching() = default;
BipartiteMatching(int V_) : V(V_), to(V_), match(V_, -1), used(V_), color(V_, -1) {}
void add_edge(int u, int v) {
assert(u >= 0 and u < V and v >= 0 and v < V and u != v);
to[u].push_back(v);
to[v].push_back(u);
}
void _bfs() {
dist.assign(V, -1);
std::vector<int> q;
int lq = 0;
for (int i = 0; i < V; i++) {
if (!color[i] and !used[i]) q.push_back(i), dist[i] = 0;
}
while (lq < int(q.size())) {
int now = q[lq++];
for (auto nxt : to[now]) {
int c = match[nxt];
if (c >= 0 and dist[c] == -1) q.push_back(c), dist[c] = dist[now] + 1;
}
}
}
bool _dfs(int now) {
vv[now] = true;
for (auto nxt : to[now]) {
int c = match[nxt];
if (c < 0 or (!vv[c] and dist[c] == dist[now] + 1 and _dfs(c))) {
match[nxt] = now, match[now] = nxt;
used[now] = true;
return true;
}
}
return false;
}
bool _color_bfs(int root) {
color[root] = 0;
std::vector<int> q{root};
int lq = 0;
while (lq < int(q.size())) {
int now = q[lq++], c = color[now];
for (auto nxt : to[now]) {
if (color[nxt] == -1) {
color[nxt] = !c, q.push_back(nxt);
} else if (color[nxt] == c) {
return false;
}
}
}
return true;
}
int solve() {
for (int i = 0; i < V; i++) {
if (color[i] == -1 and !_color_bfs(i)) return -1;
}
int ret = 0;
while (true) {
_bfs();
vv.assign(V, false);
int flow = 0;
for (int i = 0; i < V; i++) {
if (!color[i] and !used[i] and _dfs(i)) flow++;
}
if (!flow) break;
ret += flow;
}
return ret;
}
template <class OStream> friend OStream &operator<<(OStream &os, const BipartiteMatching &bm) {
os << "{N=" << bm.V << ':';
for (int i = 0; i < bm.V; i++) {
if (bm.match[i] > i) os << '(' << i << '-' << bm.match[i] << "),";
}
return os << '}';
}
};