集合 - UnionFind
参考
/// Set - Union-Find
#[derive(Debug, Clone)]
pub struct UnionFind {
data: Vec<UF>,
}
#[derive(Debug, Clone)]
enum UF {
Root(usize),
Child(usize),
}
impl UnionFind {
pub fn new(n: usize) -> Self {
UnionFind {
data: vec![UF::Root(1); n],
}
}
pub fn root(&mut self, x: usize) -> usize {
match self.data[x] {
UF::Root(_) => x,
UF::Child(parent) => {
let root = self.root(parent);
self.data[x] = UF::Child(root);
root
}
}
}
pub fn is_same(&mut self, x: usize, y: usize) -> bool {
self.root(x) == self.root(y)
}
pub fn size(&mut self, x: usize) -> usize {
let r = self.root(x);
match self.data[r] {
UF::Root(size) => size,
UF::Child(_) => 0,
}
}
pub fn merge(&mut self, x: usize, y: usize) {
let root_x = self.root(x);
let root_y = self.root(y);
if root_x != root_y {
let size_x = self.size(root_x);
let size_y = self.size(root_y);
let (i, j) = if size_x > size_y {
(root_x, root_y)
} else {
(root_y, root_x)
};
self.data[i] = UF::Root(size_x + size_y);
self.data[j] = UF::Child(i);
}
}
}
#[cfg(test)]
mod test_union_find {
use crate::set::union_find::*;
#[test]
fn it_works() {
let mut uf = UnionFind::new(10);
for i in 0..10 {
assert!(uf.is_same(i, i));
for j in 0..i {
assert!(!uf.is_same(i, j));
}
}
uf.merge(0, 1);
assert!(uf.is_same(0, 1));
uf.merge(2, 3);
assert!(uf.is_same(2, 3));
assert!(!uf.is_same(0, 3));
uf.merge(0, 3);
for i in 0..4 {
for j in 0..4 {
assert!(uf.is_same(i, j));
}
}
}
}