use std::collections::VecDeque;
type Graph = Vec<Vec<usize>>;
pub struct BipartiteMatching {
pub adj: Graph,
pub num_vertices_grp1: usize,
pub num_vertices_grp2: usize,
pub mt1: Vec<i32>,
pub mt2: Vec<i32>,
pub used: Vec<bool>,
}
impl BipartiteMatching {
pub fn new(num_vertices_grp1: usize, num_vertices_grp2: usize) -> Self {
BipartiteMatching {
adj: vec![vec![]; num_vertices_grp1 + 1],
num_vertices_grp1,
num_vertices_grp2,
mt2: vec![-1; num_vertices_grp2 + 1],
mt1: vec![-1; num_vertices_grp1 + 1],
used: vec![false; num_vertices_grp1 + 1],
}
}
#[inline]
pub fn add_edge(&mut self, u: usize, v: usize) {
self.adj[u].push(v);
}
fn try_kuhn(&mut self, cur: usize) -> bool {
if self.used[cur] {
return false;
}
self.used[cur] = true;
for i in 0..self.adj[cur].len() {
let to = self.adj[cur][i];
if self.mt2[to] == -1 || self.try_kuhn(self.mt2[to] as usize) {
self.mt2[to] = cur as i32;
return true;
}
}
false
}
pub fn kuhn(&mut self) {
self.mt2 = vec![-1; self.num_vertices_grp2 + 1];
for v in 1..self.num_vertices_grp1 + 1 {
self.used = vec![false; self.num_vertices_grp1 + 1];
self.try_kuhn(v);
}
}
pub fn print_matching(&self) {
for i in 1..self.num_vertices_grp2 + 1 {
if self.mt2[i] == -1 {
continue;
}
println!("Vertex {} in grp1 matched with {} grp2", self.mt2[i], i)
}
}
fn bfs(&self, dist: &mut [i32]) -> bool {
let mut q = VecDeque::new();
for (u, d_i) in dist
.iter_mut()
.enumerate()
.skip(1)
.take(self.num_vertices_grp1)
{
if self.mt1[u] == 0 {
*d_i = 0;
q.push_back(u);
} else {
*d_i = i32::max_value();
}
}
dist[0] = i32::max_value();
while !q.is_empty() {
let u = *q.front().unwrap();
q.pop_front();
if dist[u] < dist[0] {
for i in 0..self.adj[u].len() {
let v = self.adj[u][i];
if dist[self.mt2[v] as usize] == i32::max_value() {
dist[self.mt2[v] as usize] = dist[u] + 1;
q.push_back(self.mt2[v] as usize);
}
}
}
}
dist[0] != i32::max_value()
}
fn dfs(&mut self, u: i32, dist: &mut Vec<i32>) -> bool {
if u == 0 {
return true;
}
for i in 0..self.adj[u as usize].len() {
let v = self.adj[u as usize][i];
if dist[self.mt2[v] as usize] == dist[u as usize] + 1 && self.dfs(self.mt2[v], dist) {
self.mt2[v] = u;
self.mt1[u as usize] = v as i32;
return true;
}
}
dist[u as usize] = i32::max_value();
false
}
pub fn hopcroft_karp(&mut self) -> i32 {
self.mt2 = vec![0; self.num_vertices_grp2 + 1];
self.mt1 = vec![0; self.num_vertices_grp1 + 1];
let mut dist = vec![i32::max_value(); self.num_vertices_grp1 + 1];
let mut res = 0;
while self.bfs(&mut dist) {
for u in 1..self.num_vertices_grp1 + 1 {
if self.mt1[u] == 0 && self.dfs(u as i32, &mut dist) {
res += 1;
}
}
}
for x in self.mt2.iter_mut() {
if *x == 0 {
*x = -1;
}
}
for x in self.mt1.iter_mut() {
if *x == 0 {
*x = -1;
}
}
res
}
}
#[cfg(test)]
mod tests {
use super::*;
#[test]
fn small_graph_kuhn() {
let n1 = 6;
let n2 = 6;
let mut g = BipartiteMatching::new(n1, n2);
g.add_edge(1, 2);
g.add_edge(1, 3);
g.add_edge(3, 4);
g.add_edge(3, 1);
g.add_edge(4, 3);
g.add_edge(5, 3);
g.add_edge(5, 4);
g.add_edge(6, 6);
g.kuhn();
g.print_matching();
let answer: Vec<i32> = vec![-1, 2, -1, 1, 3, 4, 6];
for i in 1..g.mt2.len() {
if g.mt2[i] == -1 {
assert_eq!(i, 5);
continue;
}
assert!(g.mt2[i] != 2);
assert_eq!(i as i32, answer[g.mt2[i] as usize]);
}
}
#[test]
fn small_graph_hopcroft() {
let n1 = 6;
let n2 = 6;
let mut g = BipartiteMatching::new(n1, n2);
g.add_edge(1, 2);
g.add_edge(1, 3);
g.add_edge(3, 4);
g.add_edge(3, 1);
g.add_edge(4, 3);
g.add_edge(5, 3);
g.add_edge(5, 4);
g.add_edge(6, 6);
let x = g.hopcroft_karp();
assert_eq!(x, 5);
g.print_matching();
let answer: Vec<i32> = vec![-1, 2, -1, 1, 3, 4, 6];
for i in 1..g.mt2.len() {
if g.mt2[i] == -1 {
assert_eq!(i, 5);
continue;
}
assert!(g.mt2[i] != 2);
assert_eq!(i as i32, answer[g.mt2[i] as usize]);
}
}
#[test]
fn super_small_graph_kuhn() {
let n1 = 1;
let n2 = 1;
let mut g = BipartiteMatching::new(n1, n2);
g.add_edge(1, 1);
g.kuhn();
g.print_matching();
assert_eq!(g.mt2[1], 1);
}
#[test]
fn super_small_graph_hopcroft() {
let n1 = 1;
let n2 = 1;
let mut g = BipartiteMatching::new(n1, n2);
g.add_edge(1, 1);
let x = g.hopcroft_karp();
assert_eq!(x, 1);
g.print_matching();
assert_eq!(g.mt2[1], 1);
assert_eq!(g.mt1[1], 1);
}
#[test]
fn only_one_vertex_graph_kuhn() {
let n1 = 10;
let n2 = 10;
let mut g = BipartiteMatching::new(n1, n2);
g.add_edge(1, 1);
g.add_edge(2, 1);
g.add_edge(3, 1);
g.add_edge(4, 1);
g.add_edge(5, 1);
g.add_edge(6, 1);
g.add_edge(7, 1);
g.add_edge(8, 1);
g.add_edge(9, 1);
g.add_edge(10, 1);
g.kuhn();
g.print_matching();
assert_eq!(g.mt2[1], 1);
for i in 2..g.mt2.len() {
assert!(g.mt2[i] == -1);
}
}
#[test]
fn only_one_vertex_graph_hopcroft() {
let n1 = 10;
let n2 = 10;
let mut g = BipartiteMatching::new(n1, n2);
g.add_edge(1, 1);
g.add_edge(2, 1);
g.add_edge(3, 1);
g.add_edge(4, 1);
g.add_edge(5, 1);
g.add_edge(6, 1);
g.add_edge(7, 1);
g.add_edge(8, 1);
g.add_edge(9, 1);
g.add_edge(10, 1);
let x = g.hopcroft_karp();
assert_eq!(x, 1);
g.print_matching();
assert_eq!(g.mt2[1], 1);
for i in 2..g.mt2.len() {
assert!(g.mt2[i] == -1);
}
}
}