Skip to content

Bipartite Graph #413

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 8 commits into from
May 6, 2021
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
74 changes: 39 additions & 35 deletions aoj/GRL/GRL7A/main.cpp
Original file line number Diff line number Diff line change
@@ -1,51 +1,55 @@
#include <vector>
// https://onlinejudge.u-aizu.ac.jp/problems/GRL_7_A

#include <bits/stdc++.h>


// Bipartite Maximum Matching
// Memory: O(V + E)
// NOTE: undirected, bipartite
class BipartiteMaximumMatching {
int N;
std::vector<std::vector<int>> adj;
// Temporal
std::vector<int> match;
std::vector<bool> used;
size_t N;
std::vector<std::vector<size_t>> adj;

public:
// O(N)
BipartiteMaximumMatching(int n = 0): N(n), adj(n) {}
// O(1)
int size() {
// Time: O(N)
BipartiteMaximumMatching(size_t n = 0)
: N(n)
, adj(n)
{
// Do nothing
}
// Time: O(1)
size_t size() const {
return N;
}
// O(1)
void add_edge(int u, int v) {
throw_if_invalid_index(u);
throw_if_invalid_index(v);
// u = [0,N), v = [0,N)
// Time: O(1)
void add_edge(size_t u, size_t v) {
if (u >= N) throw std::out_of_range("u");
if (v >= N) throw std::out_of_range("v");
adj[u].push_back(v);
adj[v].push_back(u);
}
// O(V(V+E))
int solve(std::vector<int>& out_match) {
int ans = 0;
match.assign(N, -1);
for (int v = 0; v < N; ++v) {
if (match[v] != -1) continue;
// Time: O( V(V+E) )
size_t solve(std::vector<size_t>& match) const {
size_t ans = 0;
std::vector<bool> used(N, false);
match = std::vector<size_t>(N, N);
for (size_t v = 0; v < N; ++v) {
if (match[v] != N) continue;
used.assign(N, false);
if (dfs(v)) ans++;
if (dfs(match, used, v)) ans++;
}
out_match = std::vector<int>(match);
return ans;
}

private:
void throw_if_invalid_index(int index) {
if (index < 0 || index >= N) throw "index out of range";
}
bool dfs(int v) {
bool dfs(
std::vector<size_t>& match,
std::vector<bool>& used,
size_t v
) const {
used[v] = true;
for (int u : adj[v]) {
int w = match[u];
if (w == -1 || (!used[w] && dfs(w))) {
for (size_t u : adj[v]) {
size_t w = match[u];
if (w == N || (!used[w] && dfs(match, used, w))) {
match[v] = u;
match[u] = v;
return true;
Expand All @@ -56,9 +60,9 @@ class BipartiteMaximumMatching {
};


#include <iostream>

using namespace std;
using ll = int64_t;
using ff = long double;

int main() {
ios_base::sync_with_stdio(false);
Expand All @@ -74,7 +78,7 @@ int main() {
matching.add_edge(x, y + X);
}

vector<int> match;
vector<size_t> match;
int ans = matching.solve(match);
cout << ans << endl;

Expand Down
19 changes: 17 additions & 2 deletions lib/cpalgo/graph/README.md
Original file line number Diff line number Diff line change
Expand Up @@ -58,10 +58,25 @@ We can find all articulation points of a given graph in `O(V + E)`.
## Bipartite

### Bipartite Check
🚧
Check whether a given graph is bipartite or not.
It can be computed in `O(V)`.
`V` is the number of vertices.

[Bipartite Check | C++ code](bipartite/bipartite_check.hpp)

### Bipartite Maximum Matching
🚧
Find the maximum matching in a given bipartite graph `G`.
Kuhn's algorithm can compute the maximum matching in `O(VE)`.
`V` is the number of vertices. `E` is the number of edges.

[Bipartite Maximum Matching | C++ code](bipartite/bipartite_maximum_matching.hpp)

#### References in English
- [Kuhn's Algorithm for Maximum Bipartite Matching - Competitive Programming Algorithms](https://cp-algorithms.com/graph/kuhn_maximum_bipartite_matching.html)

#### Challenges
- [GRL_7_A < Problems | Aizu Online Judge](https://onlinejudge.u-aizu.ac.jp/problems/GRL_7_A)
- [C - 2D Plane 2N Points](https://atcoder.jp/contests/abc091/tasks/arc092_a)


## Cycle
Expand Down
55 changes: 0 additions & 55 deletions lib/cpalgo/graph/bipartite-check.hpp

This file was deleted.

61 changes: 0 additions & 61 deletions lib/cpalgo/graph/bipartite-maximum-matching.hpp

This file was deleted.

65 changes: 65 additions & 0 deletions lib/cpalgo/graph/bipartite/bipartite_check.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
#pragma once

#include <queue>
#include <stdexcept>
#include <vector>


// Bipartite Check
//
// Memory: O(V + E)
//
// NOTE:
// - undirected
// - no-multi-edge
// - self-loop
//
class BipartiteCheck {
size_t N;
std::vector<std::vector<size_t>> adj;

public:
// Time: O(V)
BipartiteCheck(size_t n = 0)
: N(n)
, adj(n)
{
// Do nothing
}
// Time: O(1)
size_t size() const {
return N;
}
// u = [0,N), v = [0,N)
// Time: O(1)
void add_edge(size_t u, size_t v) {
if (u >= N) throw std::out_of_range("u");
if (v >= N) throw std::out_of_range("v");
adj[u].push_back(v);
adj[v].push_back(u);
}
// Time: O(V)
bool solve() const {
bool is_bipartite = true;
int const UNKNOWN = 2;
std::vector<int> side(N, UNKNOWN);
std::queue<size_t> Q;
for (size_t i = 0; i < N; ++i) {
if (side[i] != UNKNOWN) continue;
Q.push(i);
side[i] = 0;
while (Q.size()) {
auto v = Q.front(); Q.pop();
for (auto u : adj[v]) {
if (side[u] == UNKNOWN) {
side[u] = side[v] ^ 1;
Q.push(u);
} else {
is_bipartite &= side[u] != side[v];
}
}
}
}
return is_bipartite;
}
};
71 changes: 71 additions & 0 deletions lib/cpalgo/graph/bipartite/bipartite_maximum_matching.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,71 @@
#pragma once

#include <stdexcept>
#include <vector>

// Bipartite Maximum Matching
//
// Space: O(V + E)
//
// NOTE:
// - undirected
// - bipartite
//
// Verified:
// - https://onlinejudge.u-aizu.ac.jp/problems/GRL_7_A
//
class BipartiteMaximumMatching {
size_t N;
std::vector<std::vector<size_t>> adj;

public:
// Time: O(N)
BipartiteMaximumMatching(size_t n = 0)
: N(n)
, adj(n)
{
// Do nothing
}
// Time: O(1)
size_t size() const {
return N;
}
// u = [0,N), v = [0,N)
// Time: O(1)
void add_edge(size_t u, size_t v) {
if (u >= N) throw std::out_of_range("u");
if (v >= N) throw std::out_of_range("v");
adj[u].push_back(v);
adj[v].push_back(u);
}
// Time: O( V(V+E) )
size_t solve(std::vector<size_t>& match) const {
size_t ans = 0;
std::vector<bool> used(N, false);
match = std::vector<size_t>(N, N);
for (size_t v = 0; v < N; ++v) {
if (match[v] != N) continue;
used.assign(N, false);
if (dfs(match, used, v)) ans++;
}
return ans;
}

private:
bool dfs(
std::vector<size_t>& match,
std::vector<bool>& used,
size_t v
) const {
used[v] = true;
for (size_t u : adj[v]) {
size_t w = match[u];
if (w == N || (!used[w] && dfs(match, used, w))) {
match[v] = u;
match[u] = v;
return true;
}
}
return false;
}
};
Loading