Skip to content

Commit 5a6faf5

Browse files
authored
Merge pull request #413 from xirc/lib/bipartite
Bipartite Graph
2 parents f6e832f + 32e9422 commit 5a6faf5

15 files changed

+633
-188
lines changed

aoj/GRL/GRL7A/main.cpp

Lines changed: 39 additions & 35 deletions
Original file line numberDiff line numberDiff line change
@@ -1,51 +1,55 @@
1-
#include <vector>
1+
// https://onlinejudge.u-aizu.ac.jp/problems/GRL_7_A
2+
3+
#include <bits/stdc++.h>
4+
25

3-
// Bipartite Maximum Matching
4-
// Memory: O(V + E)
5-
// NOTE: undirected, bipartite
66
class BipartiteMaximumMatching {
7-
int N;
8-
std::vector<std::vector<int>> adj;
9-
// Temporal
10-
std::vector<int> match;
11-
std::vector<bool> used;
7+
size_t N;
8+
std::vector<std::vector<size_t>> adj;
129

1310
public:
14-
// O(N)
15-
BipartiteMaximumMatching(int n = 0): N(n), adj(n) {}
16-
// O(1)
17-
int size() {
11+
// Time: O(N)
12+
BipartiteMaximumMatching(size_t n = 0)
13+
: N(n)
14+
, adj(n)
15+
{
16+
// Do nothing
17+
}
18+
// Time: O(1)
19+
size_t size() const {
1820
return N;
1921
}
20-
// O(1)
21-
void add_edge(int u, int v) {
22-
throw_if_invalid_index(u);
23-
throw_if_invalid_index(v);
22+
// u = [0,N), v = [0,N)
23+
// Time: O(1)
24+
void add_edge(size_t u, size_t v) {
25+
if (u >= N) throw std::out_of_range("u");
26+
if (v >= N) throw std::out_of_range("v");
2427
adj[u].push_back(v);
2528
adj[v].push_back(u);
2629
}
27-
// O(V(V+E))
28-
int solve(std::vector<int>& out_match) {
29-
int ans = 0;
30-
match.assign(N, -1);
31-
for (int v = 0; v < N; ++v) {
32-
if (match[v] != -1) continue;
30+
// Time: O( V(V+E) )
31+
size_t solve(std::vector<size_t>& match) const {
32+
size_t ans = 0;
33+
std::vector<bool> used(N, false);
34+
match = std::vector<size_t>(N, N);
35+
for (size_t v = 0; v < N; ++v) {
36+
if (match[v] != N) continue;
3337
used.assign(N, false);
34-
if (dfs(v)) ans++;
38+
if (dfs(match, used, v)) ans++;
3539
}
36-
out_match = std::vector<int>(match);
3740
return ans;
3841
}
3942

4043
private:
41-
void throw_if_invalid_index(int index) {
42-
if (index < 0 || index >= N) throw "index out of range";
43-
}
44-
bool dfs(int v) {
44+
bool dfs(
45+
std::vector<size_t>& match,
46+
std::vector<bool>& used,
47+
size_t v
48+
) const {
4549
used[v] = true;
46-
for (int u : adj[v]) {
47-
int w = match[u];
48-
if (w == -1 || (!used[w] && dfs(w))) {
50+
for (size_t u : adj[v]) {
51+
size_t w = match[u];
52+
if (w == N || (!used[w] && dfs(match, used, w))) {
4953
match[v] = u;
5054
match[u] = v;
5155
return true;
@@ -56,9 +60,9 @@ class BipartiteMaximumMatching {
5660
};
5761

5862

59-
#include <iostream>
60-
6163
using namespace std;
64+
using ll = int64_t;
65+
using ff = long double;
6266

6367
int main() {
6468
ios_base::sync_with_stdio(false);
@@ -74,7 +78,7 @@ int main() {
7478
matching.add_edge(x, y + X);
7579
}
7680

77-
vector<int> match;
81+
vector<size_t> match;
7882
int ans = matching.solve(match);
7983
cout << ans << endl;
8084

lib/cpalgo/graph/README.md

Lines changed: 17 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -58,10 +58,25 @@ We can find all articulation points of a given graph in `O(V + E)`.
5858
## Bipartite
5959

6060
### Bipartite Check
61-
🚧
61+
Check whether a given graph is bipartite or not.
62+
It can be computed in `O(V)`.
63+
`V` is the number of vertices.
64+
65+
[Bipartite Check | C++ code](bipartite/bipartite_check.hpp)
6266

6367
### Bipartite Maximum Matching
64-
🚧
68+
Find the maximum matching in a given bipartite graph `G`.
69+
Kuhn's algorithm can compute the maximum matching in `O(VE)`.
70+
`V` is the number of vertices. `E` is the number of edges.
71+
72+
[Bipartite Maximum Matching | C++ code](bipartite/bipartite_maximum_matching.hpp)
73+
74+
#### References in English
75+
- [Kuhn's Algorithm for Maximum Bipartite Matching - Competitive Programming Algorithms](https://cp-algorithms.com/graph/kuhn_maximum_bipartite_matching.html)
76+
77+
#### Challenges
78+
- [GRL_7_A < Problems | Aizu Online Judge](https://onlinejudge.u-aizu.ac.jp/problems/GRL_7_A)
79+
- [C - 2D Plane 2N Points](https://atcoder.jp/contests/abc091/tasks/arc092_a)
6580

6681

6782
## Cycle

lib/cpalgo/graph/bipartite-check.hpp

Lines changed: 0 additions & 55 deletions
This file was deleted.

lib/cpalgo/graph/bipartite-maximum-matching.hpp

Lines changed: 0 additions & 61 deletions
This file was deleted.
Lines changed: 65 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,65 @@
1+
#pragma once
2+
3+
#include <queue>
4+
#include <stdexcept>
5+
#include <vector>
6+
7+
8+
// Bipartite Check
9+
//
10+
// Memory: O(V + E)
11+
//
12+
// NOTE:
13+
// - undirected
14+
// - no-multi-edge
15+
// - self-loop
16+
//
17+
class BipartiteCheck {
18+
size_t N;
19+
std::vector<std::vector<size_t>> adj;
20+
21+
public:
22+
// Time: O(V)
23+
BipartiteCheck(size_t n = 0)
24+
: N(n)
25+
, adj(n)
26+
{
27+
// Do nothing
28+
}
29+
// Time: O(1)
30+
size_t size() const {
31+
return N;
32+
}
33+
// u = [0,N), v = [0,N)
34+
// Time: O(1)
35+
void add_edge(size_t u, size_t v) {
36+
if (u >= N) throw std::out_of_range("u");
37+
if (v >= N) throw std::out_of_range("v");
38+
adj[u].push_back(v);
39+
adj[v].push_back(u);
40+
}
41+
// Time: O(V)
42+
bool solve() const {
43+
bool is_bipartite = true;
44+
int const UNKNOWN = 2;
45+
std::vector<int> side(N, UNKNOWN);
46+
std::queue<size_t> Q;
47+
for (size_t i = 0; i < N; ++i) {
48+
if (side[i] != UNKNOWN) continue;
49+
Q.push(i);
50+
side[i] = 0;
51+
while (Q.size()) {
52+
auto v = Q.front(); Q.pop();
53+
for (auto u : adj[v]) {
54+
if (side[u] == UNKNOWN) {
55+
side[u] = side[v] ^ 1;
56+
Q.push(u);
57+
} else {
58+
is_bipartite &= side[u] != side[v];
59+
}
60+
}
61+
}
62+
}
63+
return is_bipartite;
64+
}
65+
};
Lines changed: 71 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,71 @@
1+
#pragma once
2+
3+
#include <stdexcept>
4+
#include <vector>
5+
6+
// Bipartite Maximum Matching
7+
//
8+
// Space: O(V + E)
9+
//
10+
// NOTE:
11+
// - undirected
12+
// - bipartite
13+
//
14+
// Verified:
15+
// - https://onlinejudge.u-aizu.ac.jp/problems/GRL_7_A
16+
//
17+
class BipartiteMaximumMatching {
18+
size_t N;
19+
std::vector<std::vector<size_t>> adj;
20+
21+
public:
22+
// Time: O(N)
23+
BipartiteMaximumMatching(size_t n = 0)
24+
: N(n)
25+
, adj(n)
26+
{
27+
// Do nothing
28+
}
29+
// Time: O(1)
30+
size_t size() const {
31+
return N;
32+
}
33+
// u = [0,N), v = [0,N)
34+
// Time: O(1)
35+
void add_edge(size_t u, size_t v) {
36+
if (u >= N) throw std::out_of_range("u");
37+
if (v >= N) throw std::out_of_range("v");
38+
adj[u].push_back(v);
39+
adj[v].push_back(u);
40+
}
41+
// Time: O( V(V+E) )
42+
size_t solve(std::vector<size_t>& match) const {
43+
size_t ans = 0;
44+
std::vector<bool> used(N, false);
45+
match = std::vector<size_t>(N, N);
46+
for (size_t v = 0; v < N; ++v) {
47+
if (match[v] != N) continue;
48+
used.assign(N, false);
49+
if (dfs(match, used, v)) ans++;
50+
}
51+
return ans;
52+
}
53+
54+
private:
55+
bool dfs(
56+
std::vector<size_t>& match,
57+
std::vector<bool>& used,
58+
size_t v
59+
) const {
60+
used[v] = true;
61+
for (size_t u : adj[v]) {
62+
size_t w = match[u];
63+
if (w == N || (!used[w] && dfs(match, used, w))) {
64+
match[v] = u;
65+
match[u] = v;
66+
return true;
67+
}
68+
}
69+
return false;
70+
}
71+
};

0 commit comments

Comments
 (0)