diff --git a/src/collection/iterator.rs b/src/collection.rs similarity index 60% rename from src/collection/iterator.rs rename to src/collection.rs index 9af6de0..e44f5c6 100644 --- a/src/collection/iterator.rs +++ b/src/collection.rs @@ -1,5 +1,59 @@ use std::{collections::VecDeque, ops::Range}; +pub struct Bitset { + curr: usize, + array: Vec, + len: usize, +} + +impl Iterator for Bitset { + type Item = Vec; + + fn next(&mut self) -> Option> { + if self.curr == (1 << self.len) { + return None; + } + + let mut ret = Vec::::new(); + for (i, &ai) in self.array.iter().enumerate() { + if (self.curr >> i & 1) == 1 { + ret.push(ai); + } + } + + self.curr += 1; + Some(ret) + } +} + +pub fn bitset(a: Vec) -> Bitset { + let len = a.len(); + Bitset { + curr: 0, + array: a, + len, + } +} + +#[cfg(test)] +mod test_bitset { + use crate::collection::bitset; + + #[test] + fn it_works() { + let mut bitset = bitset(vec![1, 2, 3]); + assert_eq!(bitset.next(), Some(vec![])); + assert_eq!(bitset.next(), Some(vec![1])); + assert_eq!(bitset.next(), Some(vec![2])); + assert_eq!(bitset.next(), Some(vec![1, 2])); + assert_eq!(bitset.next(), Some(vec![3])); + assert_eq!(bitset.next(), Some(vec![1, 3])); + assert_eq!(bitset.next(), Some(vec![2, 3])); + assert_eq!(bitset.next(), Some(vec![1, 2, 3])); + assert!(bitset.next().is_none()); + } +} + #[derive(Debug)] pub enum Item { Pre(usize), @@ -125,7 +179,7 @@ impl Iterator for CollectionIter<'_> { #[cfg(test)] mod test_iterator { - use crate::collection::iterator::CollectionIter; + use crate::collection::CollectionIter; fn check(iterator: CollectionIter, num_expected: usize, expected: Vec>) { let mut num_count = 0; for perm in iterator { @@ -136,7 +190,7 @@ mod test_iterator { } mod with_duplication { - use crate::collection::iterator::{test_iterator::check, CollectionIter}; + use crate::collection::{test_iterator::check, CollectionIter}; #[test] fn it_works_permutation() { @@ -199,7 +253,7 @@ mod test_iterator { } mod without_duplication { - use crate::collection::iterator::{test_iterator::check, CollectionIter}; + use crate::collection::{test_iterator::check, CollectionIter}; #[test] fn it_works_permutation() { @@ -246,3 +300,127 @@ mod test_iterator { } } } + +#[macro_export] +macro_rules! ndarray { + // ndarray!(val; *shape) + ($x:expr;) => { $x }; + ($x:expr; $size:expr $( , $rest:expr )*) => { + vec![ndarray!($x; $($rest),*); $size] + }; +} + +#[cfg(test)] +mod test_ndarray { + + #[test] + fn it_works() { + // ndarray!(val; 1) => [val] + assert_eq!(ndarray!(5; 1), vec![5]); + // ndarray!(val; 1, 2) => [[val, val]] + assert_eq!(ndarray!(5; 1, 2), vec![vec![5, 5]]); + // ndarray!(val; 2, 1) => [[val], [val]] + assert_eq!(ndarray!(5; 2, 1), vec![vec![5], vec![5]]); + } +} + +#[derive(Debug, Clone)] +pub struct UnionFind { + parents: Vec, + sizes: Vec, +} + +#[allow(clippy::needless_range_loop)] +impl UnionFind { + pub fn new(n: usize) -> Self { + Self { + parents: (0..n).collect(), + sizes: vec![1usize; n], + } + } + + pub fn parent(&mut self, x: usize) -> usize { + if self.parents[x] == x { + x + } else { + self.parents[x] = self.parent(self.parents[x]); + self.parents[x] + } + } + + pub fn unite(&mut self, x: usize, y: usize) { + let mut px = self.parent(x); + let mut py = self.parent(y); + + if px == py { + return; + } + + if self.sizes[px] < self.sizes[py] { + std::mem::swap(&mut px, &mut py); + } + + self.sizes[px] += self.sizes[py]; + self.parents[py] = px; + } + + pub fn size(&mut self, x: usize) -> usize { + let x = self.parent(x); + self.sizes[x] + } + + pub fn same(&mut self, x: usize, y: usize) -> bool { + let px = self.parent(x); + let py = self.parent(y); + px == py + } +} + +#[cfg(test)] +mod test_union_find { + use crate::collection::UnionFind; + + // helper function + fn sizes(uf: &mut UnionFind, n: usize) -> Vec { + (0..n).map(|i| uf.size(i)).collect() + } + + #[test] + fn it_works() { + let n: usize = 5; + let mut uf = UnionFind::new(n); + assert_eq!(sizes(&mut uf, n), [1, 1, 1, 1, 1]); + + uf.unite(0, 1); + assert_eq!(uf.parent(0), uf.parent(1)); + assert!(uf.same(0, 1)); + assert_ne!(uf.parent(0), uf.parent(2)); + assert!(!uf.same(0, 2)); + assert_eq!(sizes(&mut uf, n), [2, 2, 1, 1, 1]); + + // check noop + uf.unite(0, 1); + assert_eq!(uf.parent(0), uf.parent(1)); + assert!(uf.same(0, 1)); + assert_ne!(uf.parent(0), uf.parent(2)); + assert!(!uf.same(0, 2)); + assert_eq!(sizes(&mut uf, n), [2, 2, 1, 1, 1]); + + uf.unite(0, 2); + assert_eq!(uf.parent(0), uf.parent(2)); + assert!(uf.same(0, 2)); + assert_eq!(sizes(&mut uf, n), [3, 3, 3, 1, 1]); + + uf.unite(3, 4); + assert_ne!(uf.parent(0), uf.parent(3)); + assert!(!uf.same(0, 3)); + assert_eq!(sizes(&mut uf, n), [3, 3, 3, 2, 2]); + + uf.unite(0, 3); + assert_eq!(uf.parent(0), uf.parent(3)); + assert!(uf.same(0, 3)); + assert_eq!(uf.parent(0), uf.parent(4)); + assert!(uf.same(0, 4)); + assert_eq!(sizes(&mut uf, n), [5, 5, 5, 5, 5]); + } +} diff --git a/src/collection/bitset.rs b/src/collection/bitset.rs deleted file mode 100644 index ebec5cc..0000000 --- a/src/collection/bitset.rs +++ /dev/null @@ -1,53 +0,0 @@ -pub struct Bitset { - curr: usize, - array: Vec, - len: usize, -} - -impl Iterator for Bitset { - type Item = Vec; - - fn next(&mut self) -> Option> { - if self.curr == (1 << self.len) { - return None; - } - - let mut ret = Vec::::new(); - for (i, &ai) in self.array.iter().enumerate() { - if (self.curr >> i & 1) == 1 { - ret.push(ai); - } - } - - self.curr += 1; - Some(ret) - } -} - -pub fn bitset(a: Vec) -> Bitset { - let len = a.len(); - Bitset { - curr: 0, - array: a, - len, - } -} - -#[cfg(test)] -mod test_bitset { - use crate::collection::bitset; - - #[test] - fn it_works() { - let mut bitset = bitset::bitset(vec![1, 2, 3]); - assert_eq!(bitset.next(), Some(vec![])); - assert_eq!(bitset.next(), Some(vec![1])); - assert_eq!(bitset.next(), Some(vec![2])); - assert_eq!(bitset.next(), Some(vec![1, 2])); - assert_eq!(bitset.next(), Some(vec![3])); - assert_eq!(bitset.next(), Some(vec![1, 3])); - assert_eq!(bitset.next(), Some(vec![2, 3])); - assert_eq!(bitset.next(), Some(vec![1, 2, 3])); - assert!(bitset.next().is_none()); - } -} diff --git a/src/collection/mod.rs b/src/collection/mod.rs deleted file mode 100644 index 0cf968c..0000000 --- a/src/collection/mod.rs +++ /dev/null @@ -1,4 +0,0 @@ -pub mod bitset; -pub mod iterator; -pub mod ndarray; -pub mod union_find; diff --git a/src/collection/ndarray.rs b/src/collection/ndarray.rs deleted file mode 100644 index 67e9647..0000000 --- a/src/collection/ndarray.rs +++ /dev/null @@ -1,22 +0,0 @@ -#[macro_export] -macro_rules! ndarray { - // ndarray!(val; *shape) - ($x:expr;) => { $x }; - ($x:expr; $size:expr $( , $rest:expr )*) => { - vec![ndarray!($x; $($rest),*); $size] - }; -} - -#[cfg(test)] -mod test_ndarray { - - #[test] - fn it_works() { - // ndarray!(val; 1) => [val] - assert_eq!(ndarray!(5; 1), vec![5]); - // ndarray!(val; 1, 2) => [[val, val]] - assert_eq!(ndarray!(5; 1, 2), vec![vec![5, 5]]); - // ndarray!(val; 2, 1) => [[val], [val]] - assert_eq!(ndarray!(5; 2, 1), vec![vec![5], vec![5]]); - } -} diff --git a/src/collection/union_find.rs b/src/collection/union_find.rs deleted file mode 100644 index cffb65b..0000000 --- a/src/collection/union_find.rs +++ /dev/null @@ -1,100 +0,0 @@ -#[derive(Debug, Clone)] -pub struct UnionFind { - parents: Vec, - sizes: Vec, -} - -#[allow(clippy::needless_range_loop)] -impl UnionFind { - pub fn new(n: usize) -> Self { - Self { - parents: (0..n).collect(), - sizes: vec![1usize; n], - } - } - - pub fn parent(&mut self, x: usize) -> usize { - if self.parents[x] == x { - x - } else { - self.parents[x] = self.parent(self.parents[x]); - self.parents[x] - } - } - - pub fn unite(&mut self, x: usize, y: usize) { - let mut px = self.parent(x); - let mut py = self.parent(y); - - if px == py { - return; - } - - if self.sizes[px] < self.sizes[py] { - std::mem::swap(&mut px, &mut py); - } - - self.sizes[px] += self.sizes[py]; - self.parents[py] = px; - } - - pub fn size(&mut self, x: usize) -> usize { - let x = self.parent(x); - self.sizes[x] - } - - pub fn same(&mut self, x: usize, y: usize) -> bool { - let px = self.parent(x); - let py = self.parent(y); - px == py - } -} - -#[cfg(test)] -mod test_union_find { - use crate::collection::union_find::UnionFind; - - // helper function - fn sizes(uf: &mut UnionFind, n: usize) -> Vec { - (0..n).map(|i| uf.size(i)).collect() - } - - #[test] - fn it_works() { - let n: usize = 5; - let mut uf = UnionFind::new(n); - assert_eq!(sizes(&mut uf, n), [1, 1, 1, 1, 1]); - - uf.unite(0, 1); - assert_eq!(uf.parent(0), uf.parent(1)); - assert!(uf.same(0, 1)); - assert_ne!(uf.parent(0), uf.parent(2)); - assert!(!uf.same(0, 2)); - assert_eq!(sizes(&mut uf, n), [2, 2, 1, 1, 1]); - - // check noop - uf.unite(0, 1); - assert_eq!(uf.parent(0), uf.parent(1)); - assert!(uf.same(0, 1)); - assert_ne!(uf.parent(0), uf.parent(2)); - assert!(!uf.same(0, 2)); - assert_eq!(sizes(&mut uf, n), [2, 2, 1, 1, 1]); - - uf.unite(0, 2); - assert_eq!(uf.parent(0), uf.parent(2)); - assert!(uf.same(0, 2)); - assert_eq!(sizes(&mut uf, n), [3, 3, 3, 1, 1]); - - uf.unite(3, 4); - assert_ne!(uf.parent(0), uf.parent(3)); - assert!(!uf.same(0, 3)); - assert_eq!(sizes(&mut uf, n), [3, 3, 3, 2, 2]); - - uf.unite(0, 3); - assert_eq!(uf.parent(0), uf.parent(3)); - assert!(uf.same(0, 3)); - assert_eq!(uf.parent(0), uf.parent(4)); - assert!(uf.same(0, 4)); - assert_eq!(sizes(&mut uf, n), [5, 5, 5, 5, 5]); - } -} diff --git a/src/geometry.rs b/src/geometry.rs new file mode 100644 index 0000000..46e3090 --- /dev/null +++ b/src/geometry.rs @@ -0,0 +1,210 @@ +use std::collections::VecDeque; +use std::ops::{Add, Div, Mul, Sub}; + +// FIXME (himkt): Eq for Point won't work as expected. +#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] +pub struct Point(pub T, pub T); + +impl> std::ops::Add> for Point { + type Output = Point; + fn add(self, _rhs: Point) -> Self::Output { + Point(self.0 + _rhs.0, self.1 + _rhs.1) + } +} + +impl> std::ops::Sub> for Point { + type Output = Point; + fn sub(self, _rhs: Point) -> Self { + Point(self.0 - _rhs.0, self.1 - _rhs.1) + } +} + +impl> std::ops::Mul for Point { + type Output = Point; + fn mul(self, k: T) -> Self { + Self(k * self.0, k * self.1) + } +} + +impl> std::ops::Div for Point { + type Output = Self; + fn div(self, k: T) -> Self { + Self(self.0 / k, self.1 / k) + } +} + +impl + Sub> Point { + pub fn det(self, _rhs: Point) -> T { + self.0 * _rhs.1 - self.1 * _rhs.0 + } +} + +#[cfg(test)] +mod test_point { + use crate::geometry::Point; + + #[test] + fn it_works_i64() { + let p1: Point = Point(4, 6); + let p2 = Point(6, 4); + + assert_eq!(p1 + p2, Point(10, 10)); + assert_eq!(p1 - p2, Point(-2, 2)); + assert_eq!(p1 * 4, Point(16, 24)); + assert_eq!(p1 / 2, Point(2, 3)); + } + + #[test] + fn it_works_f64() { + let p1: Point = Point(4.0, 6.0); + let p2 = Point(6.0, 4.0); + + assert_eq!(p1 + p2, Point(10.0, 10.0)); + assert_eq!(p1 - p2, Point(-2.0, 2.0)); + assert_eq!(p1 * 4.0, Point(16.0, 24.0)); + assert_eq!(p1 / 2.0, Point(2.0, 3.0)); + } +} + +pub struct Line(pub Point, pub Point); + +pub trait LineAPI { + fn distance(&self, p: Point) -> f64; + fn contains_point(&self, p: Point) -> bool; +} + +// i64 +impl LineAPI for Line { + fn distance(&self, p: Point) -> f64 { + let v1 = self.1 - self.0; + let v2 = p - self.0; + let l1 = ((v1.0 * v1.0 + v1.1 * v1.1) as f64).sqrt(); + let det = v1.det(v2) as f64; + det / l1 + } + + fn contains_point(&self, p: Point) -> bool { + let d = self.1 - self.0; + let e = p - self.0; + d.1 * e.0 == d.0 * e.1 + } +} + +// f64 +impl LineAPI for Line { + fn distance(&self, p: Point) -> f64 { + let v1 = self.1 - self.0; + let v2 = p - self.0; + let l1 = (v1.0 * v1.0 + v1.1 * v1.1).sqrt(); + let det = v1.det(v2); + det / l1 + } + + fn contains_point(&self, p: Point) -> bool { + let d = self.1 - self.0; + let e = p - self.0; + d.1 * e.0 == d.0 * e.1 + } +} + +#[cfg(test)] +mod test_line { + use crate::geometry::Line; + use crate::geometry::LineAPI; + use crate::geometry::Point; + + #[test] + fn it_works_line_f64() { + let x = Point(0.0, 0.0); + let y = Point(2.0, 3.0); + let line = Line(x, y); + + let z = Point(0.0, 3.0); + let d = line.distance(z); + let d_truth = 1.664_100_588_675_687_4; + + let result = (d * 1_000_000_000.0) as i64; + let expected = (d_truth * 1_000_000_000.0) as i64; + assert_eq!(result, expected); + } + + #[test] + fn it_works_line_i64() { + let x = Point(0, 0); + let y = Point(2, 3); + let line = Line(x, y); + + let z = Point(0, 3); + let d = line.distance(z); + let d_truth = 1.664_100_588_675_687_4; + + let result = (d * 1_000_000_000.0) as i64; + let expected = (d_truth * 1_000_000_000.0) as i64; + assert_eq!(result, expected); + + // contain + assert!(line.contains_point(Point(4, 6))); + assert!(line.contains_point(Point(-2, -3))); + assert!(!line.contains_point(Point(1, 1))); + } +} + +pub fn convex_hull(ps: Vec<(i64, i64)>) -> Vec<(i64, i64)> { + let n = ps.len(); + + let mut ps: Vec> = ps.iter().map(|&(x, y)| Point::(x, y)).collect(); + + ps.sort(); + + let mut k = 0; + let mut deque: VecDeque> = VecDeque::new(); + + for &pi in &ps { + while k > 1 && (deque[k - 1] - deque[k - 2]).det(pi - deque[k - 1]) <= 0 { + deque.pop_back(); + k -= 1; + } + deque.push_back(pi); + k += 1; + } + + let t = k; + for i in (0..n - 1).rev() { + let pi = ps[i]; + while k > t && (deque[k - 1] - deque[k - 2]).det(pi - deque[k - 1]) <= 0 { + deque.pop_back(); + k -= 1; + } + deque.push_back(pi); + k += 1; + } + + let mut ret: Vec<(i64, i64)> = deque + .into_iter() + .take(k - 1) + .map(|pair| (pair.0, pair.1)) + .collect(); + + ret.sort_unstable(); + ret +} + +#[cfg(test)] +mod test_convex_hull { + use crate::geometry::convex_hull; + + #[test] + fn it_works() { + let ps = vec![(0, 0), (2, 2), (3, 1), (1, 4), (4, 4)]; + let hull = convex_hull(ps); + assert_eq!(hull, vec![(0, 0), (1, 4), (3, 1), (4, 4)]); + + let ps = vec![(0, 0), (2, 2), (4, 4)]; + let hull = convex_hull(ps); + assert_eq!(hull, vec![(0, 0), (4, 4)]); + + let ps = vec![(0, 0), (0, 1), (0, 2), (1, 1)]; + let hull = convex_hull(ps); + assert_eq!(hull, vec![(0, 0), (0, 2), (1, 1)]); + } +} diff --git a/src/geometry/convex_hull.rs b/src/geometry/convex_hull.rs deleted file mode 100644 index 673625e..0000000 --- a/src/geometry/convex_hull.rs +++ /dev/null @@ -1,62 +0,0 @@ -use crate::geometry::point::Point; -use std::collections::VecDeque; - -pub fn convex_hull(ps: Vec<(i64, i64)>) -> Vec<(i64, i64)> { - let n = ps.len(); - - let mut ps: Vec> = ps.iter().map(|&(x, y)| Point::(x, y)).collect(); - - ps.sort(); - - let mut k = 0; - let mut deque: VecDeque> = VecDeque::new(); - - for &pi in &ps { - while k > 1 && (deque[k - 1] - deque[k - 2]).det(pi - deque[k - 1]) <= 0 { - deque.pop_back(); - k -= 1; - } - deque.push_back(pi); - k += 1; - } - - let t = k; - for i in (0..n - 1).rev() { - let pi = ps[i]; - while k > t && (deque[k - 1] - deque[k - 2]).det(pi - deque[k - 1]) <= 0 { - deque.pop_back(); - k -= 1; - } - deque.push_back(pi); - k += 1; - } - - let mut ret: Vec<(i64, i64)> = deque - .into_iter() - .take(k - 1) - .map(|pair| (pair.0, pair.1)) - .collect(); - - ret.sort_unstable(); - ret -} - -#[cfg(test)] -mod test_convex_hull { - use crate::geometry::convex_hull; - - #[test] - fn it_works() { - let ps = vec![(0, 0), (2, 2), (3, 1), (1, 4), (4, 4)]; - let hull = convex_hull::convex_hull(ps); - assert_eq!(hull, vec![(0, 0), (1, 4), (3, 1), (4, 4)]); - - let ps = vec![(0, 0), (2, 2), (4, 4)]; - let hull = convex_hull::convex_hull(ps); - assert_eq!(hull, vec![(0, 0), (4, 4)]); - - let ps = vec![(0, 0), (0, 1), (0, 2), (1, 1)]; - let hull = convex_hull::convex_hull(ps); - assert_eq!(hull, vec![(0, 0), (0, 2), (1, 1)]); - } -} diff --git a/src/geometry/line.rs b/src/geometry/line.rs deleted file mode 100644 index 9091993..0000000 --- a/src/geometry/line.rs +++ /dev/null @@ -1,84 +0,0 @@ -use crate::geometry::point::Point; - -pub struct Line(pub Point, pub Point); - -pub trait LineAPI { - fn distance(&self, p: Point) -> f64; - fn contains_point(&self, p: Point) -> bool; -} - -// i64 -impl LineAPI for Line { - fn distance(&self, p: Point) -> f64 { - let v1 = self.1 - self.0; - let v2 = p - self.0; - let l1 = ((v1.0 * v1.0 + v1.1 * v1.1) as f64).sqrt(); - let det = v1.det(v2) as f64; - det / l1 - } - - fn contains_point(&self, p: Point) -> bool { - let d = self.1 - self.0; - let e = p - self.0; - d.1 * e.0 == d.0 * e.1 - } -} - -// f64 -impl LineAPI for Line { - fn distance(&self, p: Point) -> f64 { - let v1 = self.1 - self.0; - let v2 = p - self.0; - let l1 = (v1.0 * v1.0 + v1.1 * v1.1).sqrt(); - let det = v1.det(v2); - det / l1 - } - - fn contains_point(&self, p: Point) -> bool { - let d = self.1 - self.0; - let e = p - self.0; - d.1 * e.0 == d.0 * e.1 - } -} - -#[cfg(test)] -mod test_plane { - use crate::geometry::line::Line; - use crate::geometry::line::LineAPI; - use crate::geometry::line::Point; - - #[test] - fn it_works_line_f64() { - let x = Point(0.0, 0.0); - let y = Point(2.0, 3.0); - let line = Line(x, y); - - let z = Point(0.0, 3.0); - let d = line.distance(z); - let d_truth = 1.664_100_588_675_687_4; - - let result = (d * 1_000_000_000.0) as i64; - let expected = (d_truth * 1_000_000_000.0) as i64; - assert_eq!(result, expected); - } - - #[test] - fn it_works_line_i64() { - let x = Point(0, 0); - let y = Point(2, 3); - let line = Line(x, y); - - let z = Point(0, 3); - let d = line.distance(z); - let d_truth = 1.664_100_588_675_687_4; - - let result = (d * 1_000_000_000.0) as i64; - let expected = (d_truth * 1_000_000_000.0) as i64; - assert_eq!(result, expected); - - // contain - assert!(line.contains_point(Point(4, 6))); - assert!(line.contains_point(Point(-2, -3))); - assert!(!line.contains_point(Point(1, 1))); - } -} diff --git a/src/geometry/mod.rs b/src/geometry/mod.rs deleted file mode 100644 index a43aa70..0000000 --- a/src/geometry/mod.rs +++ /dev/null @@ -1,3 +0,0 @@ -pub mod convex_hull; -pub mod line; -pub mod point; diff --git a/src/geometry/point.rs b/src/geometry/point.rs deleted file mode 100644 index a78e7ee..0000000 --- a/src/geometry/point.rs +++ /dev/null @@ -1,66 +0,0 @@ -use std::ops::{Add, Div, Mul, Sub}; - -// FIXME (himkt): Eq for Point won't work as expected. -#[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd)] -pub struct Point(pub T, pub T); - -impl> std::ops::Add> for Point { - type Output = Point; - fn add(self, _rhs: Point) -> Self::Output { - Point(self.0 + _rhs.0, self.1 + _rhs.1) - } -} - -impl> std::ops::Sub> for Point { - type Output = Point; - fn sub(self, _rhs: Point) -> Self { - Point(self.0 - _rhs.0, self.1 - _rhs.1) - } -} - -impl> std::ops::Mul for Point { - type Output = Point; - fn mul(self, k: T) -> Self { - Self(k * self.0, k * self.1) - } -} - -impl> std::ops::Div for Point { - type Output = Self; - fn div(self, k: T) -> Self { - Self(self.0 / k, self.1 / k) - } -} - -impl + Sub> Point { - pub fn det(self, _rhs: Point) -> T { - self.0 * _rhs.1 - self.1 * _rhs.0 - } -} - -#[cfg(test)] -mod test_point { - use crate::geometry::point::Point; - - #[test] - fn it_works_i64() { - let p1: Point = Point(4, 6); - let p2 = Point(6, 4); - - assert_eq!(p1 + p2, Point(10, 10)); - assert_eq!(p1 - p2, Point(-2, 2)); - assert_eq!(p1 * 4, Point(16, 24)); - assert_eq!(p1 / 2, Point(2, 3)); - } - - #[test] - fn it_works_f64() { - let p1: Point = Point(4.0, 6.0); - let p2 = Point(6.0, 4.0); - - assert_eq!(p1 + p2, Point(10.0, 10.0)); - assert_eq!(p1 - p2, Point(-2.0, 2.0)); - assert_eq!(p1 * 4.0, Point(16.0, 24.0)); - assert_eq!(p1 / 2.0, Point(2.0, 3.0)); - } -} diff --git a/src/graph.rs b/src/graph.rs new file mode 100644 index 0000000..05bf8f1 --- /dev/null +++ b/src/graph.rs @@ -0,0 +1,1005 @@ +use std::collections::VecDeque; + +#[derive(Clone, Debug)] +pub struct Graph { + pub n: usize, + pub graph: Vec>, + pub rev: Vec>, + pub in_degrees: Vec, + pub out_degrees: Vec, + pub directed: bool, +} + +impl Graph { + pub fn new(n: usize, directed: bool) -> Self { + let graph: Vec> = vec![vec![]; n]; + let in_degrees = vec![0; n]; + let out_degrees = vec![0; n]; + let rev = vec![vec![]; n]; + Self { + n, + graph, + rev, + in_degrees, + out_degrees, + directed, + } + } + + pub fn connect(&mut self, from: usize, to: usize, weight: usize) { + self.graph[from].push((to, weight)); + self.out_degrees[from] += 1; + self.in_degrees[to] += 1; + + if !self.directed { + self.graph[to].push((from, weight)); + self.out_degrees[to] += 1; + self.in_degrees[from] += 1; + } + } + + pub fn connect_unweighted(&mut self, from: usize, to: usize) { + self.graph[from].push((to, 1)); + self.out_degrees[from] += 1; + self.in_degrees[to] += 1; + + if !self.directed { + self.graph[to].push((from, 1)); + self.out_degrees[to] += 1; + self.in_degrees[from] += 1; + } + } + + pub fn connect_with_residual(&mut self, from: usize, to: usize, weight: usize) { + assert!( + self.directed, + "connect_with_residual only works in directed graph." + ); + + self.graph[from].push((to, weight)); + self.out_degrees[from] += 1; + self.in_degrees[to] += 1; + + self.graph[to].push((from, 0)); + self.out_degrees[to] += 1; + self.in_degrees[from] += 1; + + self.rev[from].push(self.graph[to].len() - 1); + self.rev[to].push(self.graph[from].len() - 1); + } + + pub fn in_degree(&self, u: usize) -> usize { + self.graph[u].len() + } + + pub fn out_degree(&self, u: usize) -> usize { + self.graph[u].len() + } + + pub fn connected(&self, u: usize, v: usize) -> bool { + self.graph[u].iter().filter(|&(k, _)| &v == k).count() > 0 + } +} + +#[cfg(test)] +mod test_graph { + use crate::graph::Graph; + + #[test] + fn it_works_directed() { + let mut graph = Graph::new(6, true); + graph.connect_unweighted(0, 1); + graph.connect_unweighted(2, 5); + graph.connect(1, 0, 10); + graph.connect(3, 4, 3); + + let expected = vec![ + vec![(1, 1)], + vec![(0, 10)], + vec![(5, 1)], + vec![(4, 3)], + vec![], + vec![], + ]; + assert_eq!(graph.graph, expected); + + assert!(graph.connected(0, 1)); + assert!(graph.connected(1, 0)); + assert!(graph.connected(2, 5)); + assert!(!graph.connected(5, 2)); + assert!(graph.connected(3, 4)); + assert!(!graph.connected(4, 3)); + assert!(!graph.connected(0, 2)); + } + + #[test] + fn it_works_undirected() { + let mut graph = Graph::new(6, false); + graph.connect_unweighted(0, 1); + graph.connect(2, 4, 10); + graph.connect(5, 3, 5); + + let expected = vec![ + vec![(1, 1)], + vec![(0, 1)], + vec![(4, 10)], + vec![(5, 5)], + vec![(2, 10)], + vec![(3, 5)], + ]; + assert_eq!(graph.graph, expected); + + assert!(graph.connected(0, 1)); + assert!(graph.connected(1, 0)); + assert!(graph.connected(2, 4)); + assert!(graph.connected(4, 2)); + assert!(graph.connected(3, 5)); + assert!(graph.connected(5, 3)); + assert!(!graph.connected(1, 3)); + } + + #[test] + fn it_works_circle() { + let mut graph = Graph::new(2, false); + graph.connect_unweighted(0, 1); + + let expected = vec![vec![(1, 1)], vec![(0, 1)]]; + + assert_eq!(graph.graph, expected); + } + + #[test] + fn it_works_multiple_edge() { + let mut graph = Graph::new(2, true); + graph.connect(0, 1, 10); + graph.connect_unweighted(0, 1); + + let expected = vec![vec![(1, 10), (1, 1)], vec![]]; + assert_eq!(graph.graph, expected); + } + + #[test] + #[should_panic(expected = "connect_with_residual only works in directed graph.")] + fn it_does_not_work_residual() { + let mut graph = Graph::new(2, false); + graph.connect_with_residual(0, 1, 0) + } +} + +#[derive(Debug, Clone)] +pub struct BreadthFirstSearch { + graph: Graph, + dist: Vec, +} + +impl BreadthFirstSearch { + const INF: usize = 100_000_000_000_000_000; + + pub fn new(graph: Graph) -> Self { + let n = graph.n; + Self { + graph, + dist: vec![Self::INF; n], + } + } + + pub fn search(&mut self, root: usize) { + let mut queue = std::collections::VecDeque::new(); + queue.push_back(root); + self.dist[root] = 0; + + while let Some(cur) = queue.pop_front() { + for &(next, _) in self.graph.graph[cur].iter() { + if self.dist[next] <= self.dist[cur] + 1 { + continue; + } + + self.dist[next] = self.dist[next].min(self.dist[cur] + 1); + queue.push_back(next); + } + } + } +} + +#[cfg(test)] +mod test_bfs { + use crate::graph::BreadthFirstSearch; + use crate::graph::Graph; + + #[test] + fn it_works() { + let mut graph = Graph::new(5, true); + graph.connect_unweighted(0, 1); + graph.connect_unweighted(1, 2); + graph.connect_unweighted(2, 4); + + let mut bfs = BreadthFirstSearch::new(graph); + bfs.search(0); + assert_eq!(bfs.dist, vec![0, 1, 2, BreadthFirstSearch::INF, 3]); + } +} + +#[derive(Debug, Clone)] +pub struct DepthFirstSearch { + graph: Graph, + seen: Vec, + backptr: Vec>, + forward_history: Vec, + backward_history: Vec, +} + +#[derive(Debug)] +pub enum NodeType { + Forward(usize), + Backward(usize), +} + +impl DepthFirstSearch { + pub fn new(graph: Graph) -> Self { + let n = graph.n; + Self { + graph, + seen: vec![false; n], + backptr: vec![None; n], + forward_history: vec![], + backward_history: vec![], + } + } + + pub fn search(&mut self, root: usize) { + self.dfs(root); + } + + pub fn dfs(&mut self, u: usize) { + let mut stack = VecDeque::new(); + stack.push_front(NodeType::Backward(u)); + stack.push_front(NodeType::Forward(u)); + + self.seen[u] = true; + self.forward_history.push(u); + + while let Some(node_type) = stack.pop_front() { + match node_type { + NodeType::Forward(u) => { + for &(v, _) in self.graph.graph[u].iter() { + if self.seen[v] { + continue; + } + stack.push_front(NodeType::Backward(v)); + stack.push_front(NodeType::Forward(v)); + self.backptr[v] = Some(u); + self.seen[v] = true; + self.forward_history.push(v); + } + } + NodeType::Backward(u) => { + self.backward_history.push(u); + } + } + } + } +} + +#[cfg(test)] +mod test_dfs { + use crate::graph::DepthFirstSearch; + use crate::graph::Graph; + + #[test] + fn it_works() { + let mut graph = Graph::new(6, true); + graph.connect_unweighted(0, 1); + graph.connect_unweighted(1, 2); + graph.connect_unweighted(2, 4); + graph.connect_unweighted(2, 5); + + let mut dfs = DepthFirstSearch::new(graph); + dfs.search(0); + assert_eq!(dfs.seen, vec![true, true, true, false, true, true]); + assert_eq!(dfs.backptr, vec![None, Some(0), Some(1), None, Some(2), Some(2)]); + assert_eq!(dfs.forward_history, vec![0, 1, 2, 4, 5]); + assert_eq!(dfs.backward_history, vec![5, 4, 2, 1, 0]); + } +} + +#[derive(Debug, Clone)] +pub struct Dijkstra { + source: usize, + graph: Graph, + pub dist: Vec, + backptrs: Vec, +} + +impl Dijkstra { + const INF: usize = 100_000_000_000_000_000; + + pub fn new(graph: Graph) -> Self { + let dist: Vec = vec![Self::INF; graph.n]; + let backptrs: Vec = (0..graph.n).collect(); + Self { + source: Self::INF, + graph, + dist, + backptrs, + } + } + + pub fn search(&mut self, src: usize) { + self.source = src; + + let mut dist = vec![Self::INF; self.graph.n]; + dist[src] = 0; + + let mut queue = std::collections::BinaryHeap::new(); + queue.push((std::cmp::Reverse(0), src)); + + while let Some((std::cmp::Reverse(current_cost), current_v)) = queue.pop() { + for &(v, cost) in self.graph.graph[current_v].iter() { + if dist[v] <= current_cost + cost { + continue; + } + dist[v] = current_cost + cost; + queue.push((std::cmp::Reverse(dist[v]), v)); + self.backptrs[v] = current_v; + } + } + + self.dist = dist; + } + + pub fn shortest_path(&self, u: usize, v: usize) -> Vec<(usize, usize)> { + assert_eq!(u, self.source); + + if self.dist[v] == Self::INF { + return vec![]; + } + + let mut path = std::collections::VecDeque::new(); + + let mut cursor = v; + while cursor != u { + path.push_front((self.backptrs[cursor], cursor)); + cursor = self.backptrs[cursor]; + } + + Vec::from(path) + } +} + +#[cfg(test)] +mod test_dijkstra { + use crate::graph::Dijkstra; + use crate::graph::Graph; + + #[test] + fn it_works() { + let mut graph = Graph::new(7, true); + graph.connect(0, 1, 2); + graph.connect(0, 2, 5); + graph.connect(1, 2, 4); + graph.connect(1, 3, 5); + graph.connect(1, 4, 10); + graph.connect(2, 3, 2); + graph.connect(3, 5, 1); + graph.connect(4, 5, 5); + graph.connect(4, 6, 5); + graph.connect(5, 6, 10); + + let mut dijkstra = Dijkstra::new(graph); + dijkstra.search(0); + assert_eq!(dijkstra.dist, vec![0, 2, 5, 7, 12, 8, 17]); + + let expected = vec![(0, 1), (1, 4), (4, 6)]; + assert_eq!(dijkstra.shortest_path(0, 6), expected); + } + + #[test] + fn it_works_unreachable_path() { + let mut graph = Graph::new(9, true); + graph.connect(0, 1, 1); + graph.connect(0, 6, 10); + graph.connect(1, 2, 5); + graph.connect(1, 3, 2); + graph.connect(3, 4, 2); + graph.connect(4, 5, 3); + graph.connect(5, 6, 3); + graph.connect(7, 0, 1); + graph.connect(8, 7, 2); + + let mut dijkstra = Dijkstra::new(graph); + dijkstra.search(0); + assert_eq!( + dijkstra.dist, + vec![0, 1, 6, 3, 5, 8, 10, Dijkstra::INF, Dijkstra::INF] + ); + + assert_eq!(dijkstra.shortest_path(0, 3), vec![(0, 1), (1, 3)]); + assert_eq!(dijkstra.shortest_path(0, 8), vec![]); + } +} + +pub struct EulerTour { + graph: Graph, + l: Vec, + r: Vec, + t: usize, +} + +impl EulerTour { + const INF: usize = 100_000_000_000_000_000; + + pub fn new(n: usize, graph: Graph) -> Self { + let l = vec![Self::INF; n]; + let r = vec![Self::INF; n]; + Self { graph, l, r, t: 1 } + } + + /// Euler tour entrypoint that returns two vectors `(&l, &r)`. + /// Note that timestamp starts from `1`. + /// + /// - `l`: vector indicates the timestamp that visits a node `u` at the first time. + /// - `r`: vector indicates the timestamp that visits a node `u` at the last time. + pub fn traverse(&mut self, root: usize) -> (&[usize], &[usize]) { + self._dfs(root, None); + + for i in 0..self.l.len() { + if self.r[i] == Self::INF { + self.r[i] = self.l[i]; + } + } + + (&self.l, &self.r) + } + + fn _dfs(&mut self, u: usize, p: Option) { + self.l[u] = self.t; + self.t += 1; + + for i in 0..self.graph.graph[u].len() { + let (v, _) = self.graph.graph[u][i]; + if p != Some(v) { + self._dfs(v, Some(u)); + self.r[u] = self.t; + self.t += 1; + } + } + } +} + +#[cfg(test)] +mod test_euler_tour { + use crate::graph::EulerTour; + use crate::graph::Graph; + + #[test] + fn it_works() { + let mut graph = Graph::new(7, false); + graph.connect_unweighted(0, 1); + graph.connect_unweighted(1, 2); + graph.connect_unweighted(1, 3); + graph.connect_unweighted(3, 4); + graph.connect_unweighted(0, 5); + graph.connect_unweighted(5, 6); + + let mut euler_tour = EulerTour::new(7, graph); + let (l, r) = euler_tour.traverse(0); + + assert_eq!(l, &vec![1, 2, 3, 5, 6, 10, 11]); + assert_eq!(r, &vec![13, 8, 3, 7, 6, 12, 11]); + } +} + +pub struct FordFullkerson { + pub graph: Graph, + pub used: Vec, + pub flow: usize, +} + +impl FordFullkerson { + const INF: usize = 100_000_000_000_000_000; + + pub fn new(graph: Graph) -> Self { + let used = vec![false; graph.n]; + let flow = Self::INF; + Self { graph, used, flow } + } + + pub fn dfs(&mut self, u: usize, t: usize, f: usize) -> usize { + if u == t { + return f; + } + + self.used[u] = true; + for i in 0..self.graph.graph[u].len() { + let (v, cap) = self.graph.graph[u][i]; + let r = self.graph.rev[u][i]; + if !self.used[v] && cap > 0 { + let d = self.dfs(v, t, f.min(cap)); + + if d > 0 { + self.graph.graph[u][i].1 -= d; + self.graph.graph[v][r].1 += d; + return d; + } + } + } + + 0 + } + + pub fn solve(&mut self, s: usize, t: usize) -> usize { + let mut flow = 0; + loop { + self.used = vec![false; self.graph.n]; + let f: usize = self.dfs(s, t, FordFullkerson::INF); + if f == 0 { + return flow; + } + flow += f; + } + } +} + +#[cfg(test)] +mod test_ford_fullkerson { + use crate::graph::FordFullkerson; + use crate::graph::Graph; + + #[test] + fn it_works() { + let mut graph = Graph::new(4, true); + graph.connect_with_residual(0, 1, 2); + graph.connect_with_residual(0, 2, 1); + graph.connect_with_residual(1, 2, 1); + graph.connect_with_residual(1, 3, 1); + graph.connect_with_residual(2, 3, 2); + + let mut solver = FordFullkerson::new(graph); + let maxflow = solver.solve(0, 3); + assert_eq!(maxflow, 3); + } +} + +pub struct LowestCommonAncestor { + parents: Vec>, + depth: Vec, + graph: Graph, +} + +impl LowestCommonAncestor { + const ROOT: usize = 0; + const LOGV: usize = 30; + + pub fn new(graph: Graph) -> Self { + let n = graph.n; + let parents = vec![vec![Self::ROOT; n]; Self::LOGV]; + let depth = vec![Self::ROOT; n]; + Self { + parents, + depth, + graph, + } + } + + pub fn init(&mut self) { + self.dfs(Self::ROOT); + + for k in 0..Self::LOGV - 1 { + for v in 0..self.graph.n { + self.parents[k + 1][v] = self.parents[k][self.parents[k][v]]; + } + } + } + + fn dfs(&mut self, u: usize) { + let mut stack = VecDeque::new(); + self.parents[0][u] = u; + self.depth[u] = 0; + stack.push_front((u, u, 1)); + + while let Some((u, p, d)) = stack.pop_front() { + for &(v, _) in self.graph.graph[u].iter() { + if v == p { + continue; + } + self.parents[0][v] = u; + self.depth[v] = d + 1; + stack.push_front((v, u, d + 1)); + } + } + } + + pub fn lca(&self, mut u: usize, mut v: usize) -> usize { + if self.depth[u] > self.depth[v] { + std::mem::swap(&mut u, &mut v); + } + + for k in 0..Self::LOGV { + if (((self.depth[v] - self.depth[u]) >> k) & 1) == 1 { + v = self.parents[k][v]; + } + } + + if u == v { + return u; + } + + for k in (0..Self::LOGV).rev() { + if self.parents[k][u] != self.parents[k][v] { + u = self.parents[k][u]; + v = self.parents[k][v]; + } + } + + self.parents[0][u] + } +} + +#[cfg(test)] +mod test_lca { + use crate::graph::Graph; + use crate::graph::LowestCommonAncestor; + + #[test] + fn it_works() { + let mut graph = Graph::new(8, false); + graph.connect_unweighted(0, 1); + graph.connect_unweighted(0, 2); + graph.connect_unweighted(1, 3); + graph.connect_unweighted(1, 4); + graph.connect_unweighted(2, 5); + graph.connect_unweighted(2, 6); + graph.connect_unweighted(3, 7); + + let mut lca = LowestCommonAncestor::new(graph); + lca.init(); + + assert_eq!(lca.lca(0, 1), 0); + assert_eq!(lca.lca(7, 4), 1); + assert_eq!(lca.lca(1, 4), 1); + assert_eq!(lca.lca(4, 1), 1); + assert_eq!(lca.lca(7, 6), 0); + assert_eq!(lca.lca(5, 6), 2); + assert_eq!(lca.lca(3, 5), 0); + } + + #[test] + fn it_works_line() { + let mut graph = Graph::new(5, false); + graph.connect_unweighted(0, 1); + graph.connect_unweighted(1, 2); + graph.connect_unweighted(2, 3); + graph.connect_unweighted(3, 4); + + let mut lca = LowestCommonAncestor::new(graph); + lca.init(); + + assert_eq!(lca.lca(0, 0), 0); + assert_eq!(lca.lca(0, 1), 0); + assert_eq!(lca.lca(0, 2), 0); + assert_eq!(lca.lca(0, 3), 0); + assert_eq!(lca.lca(1, 4), 1); + assert_eq!(lca.lca(4, 1), 1); + } +} + +#[derive(Debug, Clone)] +pub struct Lowlink { + graph: Graph, + used: Vec, + ord: Vec, + low: Vec, + bridges: Vec<(usize, usize)>, +} + +#[allow(clippy::needless_range_loop)] +impl Lowlink { + pub fn new(graph: Graph) -> Self { + let n: usize = graph.n; + let used = vec![false; n]; + let ord: Vec = vec![0; n]; + let low: Vec = vec![0; n]; + let bridges: Vec<(usize, usize)> = vec![]; + + Self { + graph, + used, + ord, + low, + bridges, + } + } + + pub fn search(&mut self) { + let mut k = 0; + for u in 0..self.graph.n { + if self.used[u] { + continue; + } + k = self.dfs(u, k, None); + } + } + + pub fn dfs(&mut self, u: usize, mut k: usize, p: Option) -> usize { + self.used[u] = true; + + self.ord[u] = k; + self.low[u] = k; + k += 1; + + for i in 0..self.graph.graph[u].len() { + let (v, _) = self.graph.graph[u][i]; + + if !self.used[v] { + k = self.dfs(v, k, Some(u)); + self.low[u] = self.low[u].min(self.low[v]); + + if self.ord[u] < self.low[v] { + self.bridges.push((u.min(v), u.max(v))); + } + } else if p.is_some() && v != p.unwrap() { + self.low[u] = self.low[u].min(self.ord[v]); + } + } + + k + } + + pub fn num_bridges(&self) -> usize { + self.bridges.len() + } +} + +#[cfg(test)] +mod test_lowlink { + use crate::graph::Graph; + use crate::graph::Lowlink; + + #[test] + fn it_works() { + let mut graph = Graph::new(7, false); + graph.connect_unweighted(0, 2); + graph.connect_unweighted(1, 6); + graph.connect_unweighted(2, 3); + graph.connect_unweighted(3, 4); + graph.connect_unweighted(3, 5); + graph.connect_unweighted(4, 5); + graph.connect_unweighted(5, 6); + + let mut lowlink = Lowlink::new(graph); + lowlink.search(); + + assert_eq!(lowlink.ord, vec![0, 6, 1, 2, 3, 4, 5]); + assert_eq!(lowlink.low, vec![0, 6, 1, 2, 2, 2, 5]); + assert_eq!(lowlink.num_bridges(), 4); + } + + #[test] + fn it_works_without_bridge() { + let mut graph = Graph::new(3, false); + graph.connect_unweighted(0, 1); + graph.connect_unweighted(0, 2); + graph.connect_unweighted(1, 2); + + let mut lowlink = Lowlink::new(graph); + lowlink.search(); + + assert_eq!(lowlink.ord, vec![0, 1, 2]); + assert_eq!(lowlink.low, vec![0, 0, 0]); + assert_eq!(lowlink.num_bridges(), 0); + } + + #[test] + fn it_works_with_all_edges_are_bridges() { + let mut graph = Graph::new(6, false); + graph.connect_unweighted(0, 1); + graph.connect_unweighted(1, 2); + graph.connect_unweighted(2, 3); + graph.connect_unweighted(3, 4); + graph.connect_unweighted(4, 5); + + let mut lowlink = Lowlink::new(graph); + lowlink.search(); + + assert_eq!(lowlink.ord, vec![0, 1, 2, 3, 4, 5]); + assert_eq!(lowlink.low, vec![0, 1, 2, 3, 4, 5]); + assert_eq!(lowlink.num_bridges(), 5); + } + + #[test] + fn it_works_hand() { + let mut graph = Graph::new(7, false); + graph.connect_unweighted(0, 1); + graph.connect_unweighted(1, 2); + graph.connect_unweighted(1, 3); + graph.connect_unweighted(2, 4); + graph.connect_unweighted(4, 5); + graph.connect_unweighted(4, 6); + graph.connect_unweighted(5, 6); + + let mut lowlink = Lowlink::new(graph); + lowlink.search(); + + assert_eq!(lowlink.ord, vec![0, 1, 2, 6, 3, 4, 5]); + assert_eq!(lowlink.low, vec![0, 1, 2, 6, 3, 3, 3]); + assert_eq!(lowlink.num_bridges(), 4); + } +} + +pub struct StronglyConnectedComponent { + forward_graph: Graph, + forward_visited: Vec, + forward_visited_nodes: VecDeque, + backward_graph: Graph, + backward_visited: Vec, + topological_ranks: Vec, +} + +impl StronglyConnectedComponent { + pub fn new(graph: Graph) -> Self { + let n = graph.n; + let forward_graph = graph; + let mut backward_graph = Graph::new(n, true); + + for u in 0..n { + for &(v, _) in forward_graph.graph[u].iter() { + backward_graph.connect_unweighted(v, u); + } + } + + Self { + forward_graph, + forward_visited: vec![false; n], + forward_visited_nodes: VecDeque::new(), + backward_graph, + backward_visited: vec![false; n], + topological_ranks: vec![0; n], + } + } + + pub fn scc(&mut self) -> usize { + for u in 0..self.forward_graph.n { + if self.forward_visited[u] { + continue; + } + + self.fdfs(u); + } + + let mut topological_rank = 0; + while let Some(u) = self.forward_visited_nodes.pop_back() { + if self.backward_visited[u] { + continue; + } + + self.rdfs(u, topological_rank); + topological_rank += 1; + } + + topological_rank + } + + fn fdfs(&mut self, u: usize) { + self.forward_visited[u] = true; + + for i in 0..self.forward_graph.graph[u].len() { + let (v, _) = self.forward_graph.graph[u][i]; + + if self.forward_visited[v] { + continue; + } + + self.fdfs(v); + } + + self.forward_visited_nodes.push_back(u); + } + + fn rdfs(&mut self, u: usize, topological_rank: usize) { + self.backward_visited[u] = true; + self.topological_ranks[u] = topological_rank; + + for i in 0..self.backward_graph.graph[u].len() { + let (v, _) = self.backward_graph.graph[u][i]; + + if self.backward_visited[v] { + continue; + } + + self.rdfs(v, topological_rank); + } + } +} + +#[cfg(test)] +mod test_scc { + use crate::graph::Graph; + use crate::graph::StronglyConnectedComponent; + + #[test] + fn it_works() { + let mut graph = Graph::new(6, true); + graph.connect_unweighted(1, 4); + graph.connect_unweighted(5, 2); + graph.connect_unweighted(3, 0); + graph.connect_unweighted(5, 5); + graph.connect_unweighted(4, 1); + graph.connect_unweighted(0, 3); + graph.connect_unweighted(4, 2); + + let mut scc = StronglyConnectedComponent::new(graph); + assert_eq!(scc.scc(), 4); + assert_eq!(scc.topological_ranks, vec![3, 1, 2, 3, 1, 0]); + } +} + +pub struct TopologicalSort { + graph: Graph, +} + +#[allow(clippy::needless_range_loop)] +impl TopologicalSort { + pub fn new(graph: Graph) -> Self { + Self { graph } + } + + pub fn sort(&mut self) -> Vec { + let mut ans: Vec = vec![]; + let mut s = std::collections::BinaryHeap::new(); + let mut degrees = self.graph.in_degrees.clone(); + + for v in 0..self.graph.n { + if degrees[v] == 0 { + s.push(std::cmp::Reverse(v)); + } + } + + while let Some(std::cmp::Reverse(v)) = s.pop() { + ans.push(v); + + for &(nv, _) in self.graph.graph[v].iter() { + if degrees[nv] == 0 { + continue; + } + + degrees[nv] -= 1; + + if degrees[nv] == 0 { + s.push(std::cmp::Reverse(nv)); + } + } + } + + if ans.len() == self.graph.n { + ans + } else { + vec![] + } + } +} + +#[cfg(test)] +mod test_topological_sort { + use crate::graph::Graph; + use crate::graph::TopologicalSort; + + #[test] + fn it_works() { + let mut graph = Graph::new(4, true); + graph.connect_unweighted(1, 0); + graph.connect_unweighted(1, 3); + graph.connect_unweighted(2, 3); + + let mut sorter = TopologicalSort::new(graph); + assert_eq!(sorter.sort(), vec![1, 0, 2, 3]); + } + + #[test] + fn it_works_circle() { + let mut graph = Graph::new(2, false); + graph.connect_unweighted(0, 1); + + let mut sorter = TopologicalSort::new(graph); + assert_eq!(sorter.sort(), vec![]); + } +} diff --git a/src/graph/bfs.rs b/src/graph/bfs.rs deleted file mode 100644 index 866b8df..0000000 --- a/src/graph/bfs.rs +++ /dev/null @@ -1,54 +0,0 @@ -use crate::graph::graph::Graph; - -#[derive(Debug, Clone)] -pub struct BreadthFirstSearch { - graph: Graph, - dist: Vec, -} - -impl BreadthFirstSearch { - const INF: usize = 100_000_000_000_000_000; - - pub fn new(graph: Graph) -> Self { - let n = graph.n; - Self { - graph, - dist: vec![Self::INF; n], - } - } - - pub fn search(&mut self, root: usize) { - let mut queue = std::collections::VecDeque::new(); - queue.push_back(root); - self.dist[root] = 0; - - while let Some(cur) = queue.pop_front() { - for &(next, _) in self.graph.graph[cur].iter() { - if self.dist[next] <= self.dist[cur] + 1 { - continue; - } - - self.dist[next] = self.dist[next].min(self.dist[cur] + 1); - queue.push_back(next); - } - } - } -} - -#[cfg(test)] -mod test_bfs { - use crate::graph::bfs::BreadthFirstSearch; - use crate::graph::graph::Graph; - - #[test] - fn it_works() { - let mut graph = Graph::new(5, true); - graph.connect_unweighted(0, 1); - graph.connect_unweighted(1, 2); - graph.connect_unweighted(2, 4); - - let mut bfs = BreadthFirstSearch::new(graph); - bfs.search(0); - assert_eq!(bfs.dist, vec![0, 1, 2, BreadthFirstSearch::INF, 3]); - } -} diff --git a/src/graph/dfs.rs b/src/graph/dfs.rs deleted file mode 100644 index 1575e03..0000000 --- a/src/graph/dfs.rs +++ /dev/null @@ -1,86 +0,0 @@ -use std::collections::VecDeque; - -use crate::graph::graph::Graph; - -#[derive(Debug, Clone)] -pub struct DepthFirstSearch { - graph: Graph, - seen: Vec, - backptr: Vec>, - forward_history: Vec, - backward_history: Vec, -} - -#[derive(Debug)] -pub enum NodeType { - Forward(usize), - Backward(usize), -} - -impl DepthFirstSearch { - pub fn new(graph: Graph) -> Self { - let n = graph.n; - Self { - graph, - seen: vec![false; n], - backptr: vec![None; n], - forward_history: vec![], - backward_history: vec![], - } - } - - pub fn search(&mut self, root: usize) { - self.dfs(root); - } - - pub fn dfs(&mut self, u: usize) { - let mut stack = VecDeque::new(); - stack.push_front(NodeType::Backward(u)); - stack.push_front(NodeType::Forward(u)); - - self.seen[u] = true; - self.forward_history.push(u); - - while let Some(node_type) = stack.pop_front() { - match node_type { - NodeType::Forward(u) => { - for &(v, _) in self.graph.graph[u].iter() { - if self.seen[v] { - continue; - } - stack.push_front(NodeType::Backward(v)); - stack.push_front(NodeType::Forward(v)); - self.backptr[v] = Some(u); - self.seen[v] = true; - self.forward_history.push(v); - } - } - NodeType::Backward(u) => { - self.backward_history.push(u); - } - } - } - } -} - -#[cfg(test)] -mod test_dfs { - use crate::graph::dfs::DepthFirstSearch; - use crate::graph::graph::Graph; - - #[test] - fn it_works() { - let mut graph = Graph::new(6, true); - graph.connect_unweighted(0, 1); - graph.connect_unweighted(1, 2); - graph.connect_unweighted(2, 4); - graph.connect_unweighted(2, 5); - - let mut dfs = DepthFirstSearch::new(graph); - dfs.search(0); - assert_eq!(dfs.seen, vec![true, true, true, false, true, true]); - assert_eq!(dfs.backptr, vec![None, Some(0), Some(1), None, Some(2), Some(2)]); - assert_eq!(dfs.forward_history, vec![0, 1, 2, 4, 5]); - assert_eq!(dfs.backward_history, vec![5, 4, 2, 1, 0]); - } -} diff --git a/src/graph/dijkstra.rs b/src/graph/dijkstra.rs deleted file mode 100644 index 10ba9f2..0000000 --- a/src/graph/dijkstra.rs +++ /dev/null @@ -1,117 +0,0 @@ -use crate::graph::graph::Graph; - -#[derive(Debug, Clone)] -pub struct Dijkstra { - source: usize, - graph: Graph, - pub dist: Vec, - backptrs: Vec, -} - -impl Dijkstra { - const INF: usize = 100_000_000_000_000_000; - - pub fn new(graph: Graph) -> Self { - let dist: Vec = vec![Self::INF; graph.n]; - let backptrs: Vec = (0..graph.n).collect(); - Self { - source: Self::INF, - graph, - dist, - backptrs, - } - } - - pub fn search(&mut self, src: usize) { - self.source = src; - - let mut dist = vec![Self::INF; self.graph.n]; - dist[src] = 0; - - let mut queue = std::collections::BinaryHeap::new(); - queue.push((std::cmp::Reverse(0), src)); - - while let Some((std::cmp::Reverse(current_cost), current_v)) = queue.pop() { - for &(v, cost) in self.graph.graph[current_v].iter() { - if dist[v] <= current_cost + cost { - continue; - } - dist[v] = current_cost + cost; - queue.push((std::cmp::Reverse(dist[v]), v)); - self.backptrs[v] = current_v; - } - } - - self.dist = dist; - } - - pub fn shortest_path(&self, u: usize, v: usize) -> Vec<(usize, usize)> { - assert_eq!(u, self.source); - - if self.dist[v] == Self::INF { - return vec![]; - } - - let mut path = std::collections::VecDeque::new(); - - let mut cursor = v; - while cursor != u { - path.push_front((self.backptrs[cursor], cursor)); - cursor = self.backptrs[cursor]; - } - - Vec::from(path) - } -} - -#[cfg(test)] -mod test_dijkstra { - use crate::graph::dijkstra::Dijkstra; - use crate::graph::graph::Graph; - - #[test] - fn it_works() { - let mut graph = Graph::new(7, true); - graph.connect(0, 1, 2); - graph.connect(0, 2, 5); - graph.connect(1, 2, 4); - graph.connect(1, 3, 5); - graph.connect(1, 4, 10); - graph.connect(2, 3, 2); - graph.connect(3, 5, 1); - graph.connect(4, 5, 5); - graph.connect(4, 6, 5); - graph.connect(5, 6, 10); - - let mut dijkstra = Dijkstra::new(graph); - dijkstra.search(0); - assert_eq!(dijkstra.dist, vec![0, 2, 5, 7, 12, 8, 17]); - - let expected = vec![(0, 1), (1, 4), (4, 6)]; - assert_eq!(dijkstra.shortest_path(0, 6), expected); - } - - #[test] - fn it_works_unreachable_path() { - let mut graph = Graph::new(9, true); - graph.connect(0, 1, 1); - graph.connect(0, 6, 10); - graph.connect(1, 2, 5); - graph.connect(1, 3, 2); - graph.connect(3, 4, 2); - graph.connect(4, 5, 3); - graph.connect(5, 6, 3); - graph.connect(7, 0, 1); - graph.connect(8, 7, 2); - - let mut dijkstra = Dijkstra::new(graph); - dijkstra.search(0); - assert_eq!( - dijkstra.dist, - vec![0, 1, 6, 3, 5, 8, 10, Dijkstra::INF, Dijkstra::INF] - ); - - assert_eq!(dijkstra.shortest_path(0, 3), vec![(0, 1), (1, 3)]); - assert_eq!(dijkstra.shortest_path(0, 8), vec![]); - } -} diff --git a/src/graph/euler_tour.rs b/src/graph/euler_tour.rs deleted file mode 100644 index 540999b..0000000 --- a/src/graph/euler_tour.rs +++ /dev/null @@ -1,72 +0,0 @@ -use crate::graph::graph::Graph; - -pub struct EulerTour { - graph: Graph, - l: Vec, - r: Vec, - t: usize, -} - -impl EulerTour { - const INF: usize = 100_000_000_000_000_000; - - pub fn new(n: usize, graph: Graph) -> Self { - let l = vec![Self::INF; n]; - let r = vec![Self::INF; n]; - Self { graph, l, r, t: 1 } - } - - /// Euler tour entrypoint that returns two vectors `(&l, &r)`. - /// Note that timestamp starts from `1`. - /// - /// - `l`: vector indicates the timestamp that visits a node `u` at the first time. - /// - `r`: vector indicates the timestamp that visits a node `u` at the last time. - pub fn traverse(&mut self, root: usize) -> (&[usize], &[usize]) { - self._dfs(root, None); - - for i in 0..self.l.len() { - if self.r[i] == Self::INF { - self.r[i] = self.l[i]; - } - } - - (&self.l, &self.r) - } - - fn _dfs(&mut self, u: usize, p: Option) { - self.l[u] = self.t; - self.t += 1; - - for i in 0..self.graph.graph[u].len() { - let (v, _) = self.graph.graph[u][i]; - if p != Some(v) { - self._dfs(v, Some(u)); - self.r[u] = self.t; - self.t += 1; - } - } - } -} - -#[cfg(test)] -mod test_euler_tour { - use crate::graph::euler_tour::EulerTour; - use crate::graph::graph::Graph; - - #[test] - fn it_works() { - let mut graph = Graph::new(7, false); - graph.connect_unweighted(0, 1); - graph.connect_unweighted(1, 2); - graph.connect_unweighted(1, 3); - graph.connect_unweighted(3, 4); - graph.connect_unweighted(0, 5); - graph.connect_unweighted(5, 6); - - let mut euler_tour = EulerTour::new(7, graph); - let (l, r) = euler_tour.traverse(0); - - assert_eq!(l, &vec![1, 2, 3, 5, 6, 10, 11]); - assert_eq!(r, &vec![13, 8, 3, 7, 6, 12, 11]); - } -} diff --git a/src/graph/ford_fullkerson.rs b/src/graph/ford_fullkerson.rs deleted file mode 100644 index 7412009..0000000 --- a/src/graph/ford_fullkerson.rs +++ /dev/null @@ -1,72 +0,0 @@ -use crate::graph::graph::Graph; - -pub struct FordFullkerson { - pub graph: Graph, - pub used: Vec, - pub flow: usize, -} - -impl FordFullkerson { - const INF: usize = 100_000_000_000_000_000; - - pub fn new(graph: Graph) -> Self { - let used = vec![false; graph.n]; - let flow = Self::INF; - Self { graph, used, flow } - } - - pub fn dfs(&mut self, u: usize, t: usize, f: usize) -> usize { - if u == t { - return f; - } - - self.used[u] = true; - for i in 0..self.graph.graph[u].len() { - let (v, cap) = self.graph.graph[u][i]; - let r = self.graph.rev[u][i]; - if !self.used[v] && cap > 0 { - let d = self.dfs(v, t, f.min(cap)); - - if d > 0 { - self.graph.graph[u][i].1 -= d; - self.graph.graph[v][r].1 += d; - return d; - } - } - } - - 0 - } - - pub fn solve(&mut self, s: usize, t: usize) -> usize { - let mut flow = 0; - loop { - self.used = vec![false; self.graph.n]; - let f: usize = self.dfs(s, t, FordFullkerson::INF); - if f == 0 { - return flow; - } - flow += f; - } - } -} - -#[cfg(test)] -mod test_lowlink { - use crate::graph::ford_fullkerson::FordFullkerson; - use crate::graph::graph::Graph; - - #[test] - fn it_works() { - let mut graph = Graph::new(4, true); - graph.connect_with_residual(0, 1, 2); - graph.connect_with_residual(0, 2, 1); - graph.connect_with_residual(1, 2, 1); - graph.connect_with_residual(1, 3, 1); - graph.connect_with_residual(2, 3, 2); - - let mut solver = FordFullkerson::new(graph); - let maxflow = solver.solve(0, 3); - assert_eq!(maxflow, 3); - } -} diff --git a/src/graph/graph.rs b/src/graph/graph.rs deleted file mode 100644 index d2674b2..0000000 --- a/src/graph/graph.rs +++ /dev/null @@ -1,165 +0,0 @@ -#[derive(Clone, Debug)] -pub struct Graph { - pub n: usize, - pub graph: Vec>, - pub rev: Vec>, - pub in_degrees: Vec, - pub out_degrees: Vec, - pub directed: bool, -} - -impl Graph { - pub fn new(n: usize, directed: bool) -> Self { - let graph: Vec> = vec![vec![]; n]; - let in_degrees = vec![0; n]; - let out_degrees = vec![0; n]; - let rev = vec![vec![]; n]; - Self { - n, - graph, - rev, - in_degrees, - out_degrees, - directed, - } - } - - pub fn connect(&mut self, from: usize, to: usize, weight: usize) { - self.graph[from].push((to, weight)); - self.out_degrees[from] += 1; - self.in_degrees[to] += 1; - - if !self.directed { - self.graph[to].push((from, weight)); - self.out_degrees[to] += 1; - self.in_degrees[from] += 1; - } - } - - pub fn connect_unweighted(&mut self, from: usize, to: usize) { - self.graph[from].push((to, 1)); - self.out_degrees[from] += 1; - self.in_degrees[to] += 1; - - if !self.directed { - self.graph[to].push((from, 1)); - self.out_degrees[to] += 1; - self.in_degrees[from] += 1; - } - } - - pub fn connect_with_residual(&mut self, from: usize, to: usize, weight: usize) { - assert!( - self.directed, - "connect_with_residual only works in directed graph." - ); - - self.graph[from].push((to, weight)); - self.out_degrees[from] += 1; - self.in_degrees[to] += 1; - - self.graph[to].push((from, 0)); - self.out_degrees[to] += 1; - self.in_degrees[from] += 1; - - self.rev[from].push(self.graph[to].len() - 1); - self.rev[to].push(self.graph[from].len() - 1); - } - - pub fn in_degree(&self, u: usize) -> usize { - self.graph[u].len() - } - - pub fn out_degree(&self, u: usize) -> usize { - self.graph[u].len() - } - - pub fn connected(&self, u: usize, v: usize) -> bool { - self.graph[u].iter().filter(|&(k, _)| &v == k).count() > 0 - } -} - -#[cfg(test)] -mod test_graph { - use crate::graph::graph::Graph; - - #[test] - fn it_works_directed() { - let mut graph = Graph::new(6, true); - graph.connect_unweighted(0, 1); - graph.connect_unweighted(2, 5); - graph.connect(1, 0, 10); - graph.connect(3, 4, 3); - - let expected = vec![ - vec![(1, 1)], - vec![(0, 10)], - vec![(5, 1)], - vec![(4, 3)], - vec![], - vec![], - ]; - assert_eq!(graph.graph, expected); - - assert!(graph.connected(0, 1)); - assert!(graph.connected(1, 0)); - assert!(graph.connected(2, 5)); - assert!(!graph.connected(5, 2)); - assert!(graph.connected(3, 4)); - assert!(!graph.connected(4, 3)); - assert!(!graph.connected(0, 2)); - } - - #[test] - fn it_works_undirected() { - let mut graph = Graph::new(6, false); - graph.connect_unweighted(0, 1); - graph.connect(2, 4, 10); - graph.connect(5, 3, 5); - - let expected = vec![ - vec![(1, 1)], - vec![(0, 1)], - vec![(4, 10)], - vec![(5, 5)], - vec![(2, 10)], - vec![(3, 5)], - ]; - assert_eq!(graph.graph, expected); - - assert!(graph.connected(0, 1)); - assert!(graph.connected(1, 0)); - assert!(graph.connected(2, 4)); - assert!(graph.connected(4, 2)); - assert!(graph.connected(3, 5)); - assert!(graph.connected(5, 3)); - assert!(!graph.connected(1, 3)); - } - - #[test] - fn it_works_circle() { - let mut graph = Graph::new(2, false); - graph.connect_unweighted(0, 1); - - let expected = vec![vec![(1, 1)], vec![(0, 1)]]; - - assert_eq!(graph.graph, expected); - } - - #[test] - fn it_works_multiple_edge() { - let mut graph = Graph::new(2, true); - graph.connect(0, 1, 10); - graph.connect_unweighted(0, 1); - - let expected = vec![vec![(1, 10), (1, 1)], vec![]]; - assert_eq!(graph.graph, expected); - } - - #[test] - #[should_panic(expected = "connect_with_residual only works in directed graph.")] - fn it_does_not_work_residual() { - let mut graph = Graph::new(2, false); - graph.connect_with_residual(0, 1, 0) - } -} diff --git a/src/graph/lca.rs b/src/graph/lca.rs deleted file mode 100644 index 04e2438..0000000 --- a/src/graph/lca.rs +++ /dev/null @@ -1,126 +0,0 @@ -use std::collections::VecDeque; - -use crate::graph::graph::Graph; - -pub struct LowestCommonAncestor { - parents: Vec>, - depth: Vec, - graph: Graph, -} - -impl LowestCommonAncestor { - const ROOT: usize = 0; - const LOGV: usize = 30; - - pub fn new(graph: Graph) -> Self { - let n = graph.n; - let parents = vec![vec![Self::ROOT; n]; Self::LOGV]; - let depth = vec![Self::ROOT; n]; - Self { - parents, - depth, - graph, - } - } - - pub fn init(&mut self) { - self.dfs(Self::ROOT); - - for k in 0..Self::LOGV - 1 { - for v in 0..self.graph.n { - self.parents[k + 1][v] = self.parents[k][self.parents[k][v]]; - } - } - } - - fn dfs(&mut self, u: usize) { - let mut stack = VecDeque::new(); - self.parents[0][u] = u; - self.depth[u] = 0; - stack.push_front((u, u, 1)); - - while let Some((u, p, d)) = stack.pop_front() { - for &(v, _) in self.graph.graph[u].iter() { - if v == p { - continue; - } - self.parents[0][v] = u; - self.depth[v] = d + 1; - stack.push_front((v, u, d + 1)); - } - } - } - - pub fn lca(&self, mut u: usize, mut v: usize) -> usize { - if self.depth[u] > self.depth[v] { - std::mem::swap(&mut u, &mut v); - } - - for k in 0..Self::LOGV { - if (((self.depth[v] - self.depth[u]) >> k) & 1) == 1 { - v = self.parents[k][v]; - } - } - - if u == v { - return u; - } - - for k in (0..Self::LOGV).rev() { - if self.parents[k][u] != self.parents[k][v] { - u = self.parents[k][u]; - v = self.parents[k][v]; - } - } - - self.parents[0][u] - } -} - -#[cfg(test)] -mod test_lca { - use crate::graph::graph::Graph; - use crate::graph::lca::LowestCommonAncestor; - - #[test] - fn it_works() { - let mut graph = Graph::new(8, false); - graph.connect_unweighted(0, 1); - graph.connect_unweighted(0, 2); - graph.connect_unweighted(1, 3); - graph.connect_unweighted(1, 4); - graph.connect_unweighted(2, 5); - graph.connect_unweighted(2, 6); - graph.connect_unweighted(3, 7); - - let mut lca = LowestCommonAncestor::new(graph); - lca.init(); - - assert_eq!(lca.lca(0, 1), 0); - assert_eq!(lca.lca(7, 4), 1); - assert_eq!(lca.lca(1, 4), 1); - assert_eq!(lca.lca(4, 1), 1); - assert_eq!(lca.lca(7, 6), 0); - assert_eq!(lca.lca(5, 6), 2); - assert_eq!(lca.lca(3, 5), 0); - } - - #[test] - fn it_works_line() { - let mut graph = Graph::new(5, false); - graph.connect_unweighted(0, 1); - graph.connect_unweighted(1, 2); - graph.connect_unweighted(2, 3); - graph.connect_unweighted(3, 4); - - let mut lca = LowestCommonAncestor::new(graph); - lca.init(); - - assert_eq!(lca.lca(0, 0), 0); - assert_eq!(lca.lca(0, 1), 0); - assert_eq!(lca.lca(0, 2), 0); - assert_eq!(lca.lca(0, 3), 0); - assert_eq!(lca.lca(1, 4), 1); - assert_eq!(lca.lca(4, 1), 1); - } -} diff --git a/src/graph/lowlink.rs b/src/graph/lowlink.rs deleted file mode 100644 index ab0cc4a..0000000 --- a/src/graph/lowlink.rs +++ /dev/null @@ -1,144 +0,0 @@ -use crate::graph::graph::Graph; - -#[derive(Debug, Clone)] -pub struct Lowlink { - graph: Graph, - used: Vec, - ord: Vec, - low: Vec, - bridges: Vec<(usize, usize)>, -} - -#[allow(clippy::needless_range_loop)] -impl Lowlink { - pub fn new(graph: Graph) -> Self { - let n: usize = graph.n; - let used = vec![false; n]; - let ord: Vec = vec![0; n]; - let low: Vec = vec![0; n]; - let bridges: Vec<(usize, usize)> = vec![]; - - Self { - graph, - used, - ord, - low, - bridges, - } - } - - pub fn search(&mut self) { - let mut k = 0; - for u in 0..self.graph.n { - if self.used[u] { - continue; - } - k = self.dfs(u, k, None); - } - } - - pub fn dfs(&mut self, u: usize, mut k: usize, p: Option) -> usize { - self.used[u] = true; - - self.ord[u] = k; - self.low[u] = k; - k += 1; - - for i in 0..self.graph.graph[u].len() { - let (v, _) = self.graph.graph[u][i]; - - if !self.used[v] { - k = self.dfs(v, k, Some(u)); - self.low[u] = self.low[u].min(self.low[v]); - - if self.ord[u] < self.low[v] { - self.bridges.push((u.min(v), u.max(v))); - } - } else if p.is_some() && v != p.unwrap() { - self.low[u] = self.low[u].min(self.ord[v]); - } - } - - k - } - - pub fn num_bridges(&self) -> usize { - self.bridges.len() - } -} - -#[cfg(test)] -mod test_lowlink { - use crate::graph::graph::Graph; - use crate::graph::lowlink::Lowlink; - - #[test] - fn it_works() { - let mut graph = Graph::new(7, false); - graph.connect_unweighted(0, 2); - graph.connect_unweighted(1, 6); - graph.connect_unweighted(2, 3); - graph.connect_unweighted(3, 4); - graph.connect_unweighted(3, 5); - graph.connect_unweighted(4, 5); - graph.connect_unweighted(5, 6); - - let mut lowlink = Lowlink::new(graph); - lowlink.search(); - - assert_eq!(lowlink.ord, vec![0, 6, 1, 2, 3, 4, 5]); - assert_eq!(lowlink.low, vec![0, 6, 1, 2, 2, 2, 5]); - assert_eq!(lowlink.num_bridges(), 4); - } - - #[test] - fn it_works_without_bridge() { - let mut graph = Graph::new(3, false); - graph.connect_unweighted(0, 1); - graph.connect_unweighted(0, 2); - graph.connect_unweighted(1, 2); - - let mut lowlink = Lowlink::new(graph); - lowlink.search(); - - assert_eq!(lowlink.ord, vec![0, 1, 2]); - assert_eq!(lowlink.low, vec![0, 0, 0]); - assert_eq!(lowlink.num_bridges(), 0); - } - - #[test] - fn it_works_with_all_edges_are_bridges() { - let mut graph = Graph::new(6, false); - graph.connect_unweighted(0, 1); - graph.connect_unweighted(1, 2); - graph.connect_unweighted(2, 3); - graph.connect_unweighted(3, 4); - graph.connect_unweighted(4, 5); - - let mut lowlink = Lowlink::new(graph); - lowlink.search(); - - assert_eq!(lowlink.ord, vec![0, 1, 2, 3, 4, 5]); - assert_eq!(lowlink.low, vec![0, 1, 2, 3, 4, 5]); - assert_eq!(lowlink.num_bridges(), 5); - } - - #[test] - fn it_works_hand() { - let mut graph = Graph::new(7, false); - graph.connect_unweighted(0, 1); - graph.connect_unweighted(1, 2); - graph.connect_unweighted(1, 3); - graph.connect_unweighted(2, 4); - graph.connect_unweighted(4, 5); - graph.connect_unweighted(4, 6); - graph.connect_unweighted(5, 6); - - let mut lowlink = Lowlink::new(graph); - lowlink.search(); - - assert_eq!(lowlink.ord, vec![0, 1, 2, 6, 3, 4, 5]); - assert_eq!(lowlink.low, vec![0, 1, 2, 6, 3, 3, 3]); - assert_eq!(lowlink.num_bridges(), 4); - } -} diff --git a/src/graph/mod.rs b/src/graph/mod.rs deleted file mode 100644 index 90da200..0000000 --- a/src/graph/mod.rs +++ /dev/null @@ -1,11 +0,0 @@ -pub mod bfs; -pub mod dfs; -pub mod dijkstra; -pub mod euler_tour; -pub mod ford_fullkerson; -#[allow(clippy::module_inception)] -pub mod graph; -pub mod lca; -pub mod lowlink; -pub mod scc; -pub mod topological_sort; diff --git a/src/graph/scc.rs b/src/graph/scc.rs deleted file mode 100644 index f0a0d6f..0000000 --- a/src/graph/scc.rs +++ /dev/null @@ -1,110 +0,0 @@ -use crate::graph::graph::Graph; - -use std::collections::VecDeque; - -pub struct StronglyConnectedComponent { - forward_graph: Graph, - forward_visited: Vec, - forward_visited_nodes: VecDeque, - backward_graph: Graph, - backward_visited: Vec, - topological_ranks: Vec, -} - -impl StronglyConnectedComponent { - pub fn new(graph: Graph) -> Self { - let n = graph.n; - let forward_graph = graph; - let mut backward_graph = Graph::new(n, true); - - for u in 0..n { - for &(v, _) in forward_graph.graph[u].iter() { - backward_graph.connect_unweighted(v, u); - } - } - - Self { - forward_graph, - forward_visited: vec![false; n], - forward_visited_nodes: VecDeque::new(), - backward_graph, - backward_visited: vec![false; n], - topological_ranks: vec![0; n], - } - } - - pub fn scc(&mut self) -> usize { - for u in 0..self.forward_graph.n { - if self.forward_visited[u] { - continue; - } - - self.fdfs(u); - } - - let mut topological_rank = 0; - while let Some(u) = self.forward_visited_nodes.pop_back() { - if self.backward_visited[u] { - continue; - } - - self.rdfs(u, topological_rank); - topological_rank += 1; - } - - topological_rank - } - - fn fdfs(&mut self, u: usize) { - self.forward_visited[u] = true; - - for i in 0..self.forward_graph.graph[u].len() { - let (v, _) = self.forward_graph.graph[u][i]; - - if self.forward_visited[v] { - continue; - } - - self.fdfs(v); - } - - self.forward_visited_nodes.push_back(u); - } - - fn rdfs(&mut self, u: usize, topological_rank: usize) { - self.backward_visited[u] = true; - self.topological_ranks[u] = topological_rank; - - for i in 0..self.backward_graph.graph[u].len() { - let (v, _) = self.backward_graph.graph[u][i]; - - if self.backward_visited[v] { - continue; - } - - self.rdfs(v, topological_rank); - } - } -} - -#[cfg(test)] -mod test_scc { - use crate::graph::graph::Graph; - use crate::graph::scc::StronglyConnectedComponent; - - #[test] - fn it_works() { - let mut graph = Graph::new(6, true); - graph.connect_unweighted(1, 4); - graph.connect_unweighted(5, 2); - graph.connect_unweighted(3, 0); - graph.connect_unweighted(5, 5); - graph.connect_unweighted(4, 1); - graph.connect_unweighted(0, 3); - graph.connect_unweighted(4, 2); - - let mut scc = StronglyConnectedComponent::new(graph); - assert_eq!(scc.scc(), 4); - assert_eq!(scc.topological_ranks, vec![3, 1, 2, 3, 1, 0]); - } -} diff --git a/src/graph/topological_sort.rs b/src/graph/topological_sort.rs deleted file mode 100644 index dd8c556..0000000 --- a/src/graph/topological_sort.rs +++ /dev/null @@ -1,72 +0,0 @@ -use crate::graph::graph::Graph; - -pub struct TopologicalSort { - graph: Graph, -} - -#[allow(clippy::needless_range_loop)] -impl TopologicalSort { - pub fn new(graph: Graph) -> Self { - Self { graph } - } - - pub fn sort(&mut self) -> Vec { - let mut ans: Vec = vec![]; - let mut s = std::collections::BinaryHeap::new(); - let mut degrees = self.graph.in_degrees.clone(); - - for v in 0..self.graph.n { - if degrees[v] == 0 { - s.push(std::cmp::Reverse(v)); - } - } - - while let Some(std::cmp::Reverse(v)) = s.pop() { - ans.push(v); - - for &(nv, _) in self.graph.graph[v].iter() { - if degrees[nv] == 0 { - continue; - } - - degrees[nv] -= 1; - - if degrees[nv] == 0 { - s.push(std::cmp::Reverse(nv)); - } - } - } - - if ans.len() == self.graph.n { - ans - } else { - vec![] - } - } -} - -#[cfg(test)] -mod test_topological_sort { - use crate::graph::graph::Graph; - use crate::graph::topological_sort::TopologicalSort; - - #[test] - fn it_works() { - let mut graph = Graph::new(4, true); - graph.connect_unweighted(1, 0); - graph.connect_unweighted(1, 3); - graph.connect_unweighted(2, 3); - - let mut sorter = TopologicalSort::new(graph); - assert_eq!(sorter.sort(), vec![1, 0, 2, 3]); - } - - #[test] - fn it_works_circle() { - let mut graph = Graph::new(2, false); - graph.connect_unweighted(0, 1); - - let mut sorter = TopologicalSort::new(graph); - assert_eq!(sorter.sort(), vec![]); - } -} diff --git a/src/math.rs b/src/math.rs new file mode 100644 index 0000000..a1d4376 --- /dev/null +++ b/src/math.rs @@ -0,0 +1,319 @@ +pub fn com(n: i64, mut r: i64) -> i64 { + if r > n { + return 0; + } + + if r * 2 > n { + r = n - r; + } + + if r == 0 { + return 1; + } + + let mut res = 1; + for i in 1..(r + 1) { + res *= n - i + 1; + res /= i; + } + + res +} + +#[cfg(test)] +mod test_com { + use crate::math::com; + + #[test] + fn it_works() { + assert_eq!(com(6, 0), 1); + assert_eq!(com(6, 1), 6); + assert_eq!(com(6, 2), 15); + assert_eq!(com(6, 3), 20); + assert_eq!(com(6, 4), 15); + assert_eq!(com(6, 5), 6); + assert_eq!(com(6, 6), 1); + } +} + +pub fn eratosthenes_sieve(n: usize) -> Vec { + let mut s = vec![true; n]; + s[0] = false; + s[1] = false; + + for i in 2..n { + if i * i > n { + break; + } + if s[i] { + for k in 2..(n + i - 1) / i { + s[k * i] = false + } + } + } + + s +} + +#[cfg(test)] +mod test_eratosthenes_sieve { + use crate::math::eratosthenes_sieve; + + #[test] + fn it_works() { + let primes = eratosthenes_sieve(10); + + assert!(!primes[1]); + assert!(primes[2]); + assert!(primes[3]); + assert!(!primes[4]); + assert!(primes[5]); + assert!(!primes[6]); + assert!(primes[7]); + assert!(!primes[8]); + assert!(!primes[9]); + } +} + +pub fn gcd(a: i64, b: i64) -> i64 { + if b == 0 { + a + } else { + gcd(b, a % b) + } +} + +#[cfg(test)] +mod test_gcd { + use crate::math::gcd; + + #[test] + fn it_works() { + assert_eq!(gcd(15, 5), 5); + assert_eq!(gcd(5, 15), 5); + assert_eq!(gcd(198, 26), 2); + assert_eq!(gcd(26, 198), 2); + } +} + +pub fn modcom(n: usize, k: usize, div: usize) -> usize { + let mut fact = Vec::::new(); + let mut inv = Vec::::new(); + let mut finv = Vec::::new(); + + let upper = n + 1; + + fact.resize(upper, 0); + inv.resize(upper, 0); + finv.resize(upper, 0); + + fact[0] = 1; + fact[1] = 1; + + finv[0] = 1; + finv[1] = 1; + + inv[1] = 1; + + for i in 2..upper { + fact[i] = fact[i - 1] * i % div; + inv[i] = div - inv[div % i] * (div / i) % div; + finv[i] = finv[i - 1] * inv[i] % div; + } + + fact[n] * (finv[k] * finv[n - k] % div) % div +} + +#[cfg(test)] +mod test_modcom { + use crate::math::modcom; + + #[test] + fn it_works() { + assert_eq!(modcom(6, 0, 7), 1); + assert_eq!(modcom(6, 1, 7), 6); + assert_eq!(modcom(6, 2, 7), 1); + assert_eq!(modcom(6, 3, 7), 6); + assert_eq!(modcom(6, 4, 7), 1); + assert_eq!(modcom(6, 5, 7), 6); + assert_eq!(modcom(6, 6, 7), 1); + } +} + +pub fn modpow(mut a: usize, mut n: usize, m: usize) -> usize { + let mut ans = 1; + + while n > 0 { + if n & 1 == 1 { + ans = ans * a % m; + } + + a = a * a % m; + n >>= 1; + } + + ans +} + +#[cfg(test)] +mod test_modpow { + use crate::math::modpow; + + #[test] + fn it_works() { + assert_eq!(modpow(2, 10, 1_000_000_007), 1024); + assert_eq!(modpow(2, 3, 1_000_000_007), 8); + assert_eq!(modpow(5, 8, 1_000_000_007), 390625); + assert_eq!(modpow(2, 2, 3), 1); + assert_eq!(modpow(2, 3, 3), 2); + } +} + +pub fn phi(mut n: usize) -> usize { + let mut res = n; + + let mut i = 2; + while i * i <= n { + if n % i == 0 { + res = res / i * (i - 1); + while n % i == 0 { + n /= i; + } + } + i += 1; + } + + if n != 1 { + res = res / n * (n - 1); + } + + res +} + +pub fn modinv(a: usize, p: usize) -> usize { + let m = phi(p); + modpow(a, m - 1, p) +} + +#[cfg(test)] +mod test_modinv { + use crate::math::modinv; + use crate::math::modpow; + + fn inv_euler(a: usize, p: usize) -> usize { + modpow(a, p - 2, p) + } + + fn inv_simple(a: usize, p: usize) -> usize { + let mut ret = 1; + loop { + if (a * ret) % p == 1 { + return ret; + } + ret += 1; + } + } + + #[test] + fn it_works_prime() { + // 10^-1 mod 7 + assert_eq!(modinv(10, 7), inv_euler(10, 7)); + } + + #[test] + fn it_works_composite() { + // 10^-1 mod 2019 + assert_eq!(modinv(10, 2019), inv_simple(10, 2019)); + } +} + +#[derive(Debug, Clone)] +pub struct SequentialPrimeFactorization { + smallest_prime_factors: Vec, +} + +impl SequentialPrimeFactorization { + pub fn new(n: usize) -> Self { + let mut smallest_prime_factors: Vec = (0..=(n + 1)).collect(); + let mut i = 2; + + while i * i <= n { + if smallest_prime_factors[i] == i { + let mut j = i; + while j * i <= n { + smallest_prime_factors[j * i] = i; + j += 1; + } + } + + i += 1; + } + + Self { + smallest_prime_factors, + } + } + + pub fn factorize(&self, mut x: usize) -> Vec { + let mut ret: Vec = vec![]; + while x != 1 { + ret.push(self.smallest_prime_factors[x]); + x /= self.smallest_prime_factors[x]; + } + + ret.sort_unstable(); + ret + } +} + +pub fn prime_factorize(mut n: usize) -> Vec<(usize, usize)> { + let mut ret = vec![]; + let mut p = 2; + + while p * p <= n { + if n % p == 0 { + let mut k = 0; + while n % p == 0 { + k += 1; + n /= p; + } + ret.push((p, k)); + } + + p += 1; + } + + if n != 1 { + ret.push((n, 1)); + } + ret +} + +#[cfg(test)] +mod test_prime_factorization { + use crate::math::prime_factorize; + use crate::math::SequentialPrimeFactorization; + + #[test] + fn it_works_sequential_prime_factorization() { + let prime_factorizer = SequentialPrimeFactorization::new(100); + + assert_eq!(prime_factorizer.factorize(1), vec![]); + assert_eq!(prime_factorizer.factorize(2), vec![2]); + assert_eq!(prime_factorizer.factorize(4), vec![2, 2]); + assert_eq!(prime_factorizer.factorize(7), vec![7]); + assert_eq!(prime_factorizer.factorize(30), vec![2, 3, 5]); + assert_eq!(prime_factorizer.factorize(23), vec![23]); + } + + #[test] + fn it_works_prime_factorization() { + assert_eq!(prime_factorize(1), vec![]); + assert_eq!(prime_factorize(2), vec![(2, 1)]); + assert_eq!(prime_factorize(4), vec![(2, 2)]); + assert_eq!(prime_factorize(7), vec![(7, 1)]); + assert_eq!(prime_factorize(30), vec![(2, 1), (3, 1), (5, 1)]); + assert_eq!(prime_factorize(23), vec![(23, 1)]); + assert_eq!(prime_factorize(512), vec![(2, 9)]); + } +} diff --git a/src/math/com.rs b/src/math/com.rs deleted file mode 100644 index f59ad18..0000000 --- a/src/math/com.rs +++ /dev/null @@ -1,37 +0,0 @@ -pub fn com(n: i64, mut r: i64) -> i64 { - if r > n { - return 0; - } - - if r * 2 > n { - r = n - r; - } - - if r == 0 { - return 1; - } - - let mut res = 1; - for i in 1..(r + 1) { - res *= n - i + 1; - res /= i; - } - - res -} - -#[cfg(test)] -mod test_combination { - use crate::math::com::com; - - #[test] - fn it_works() { - assert_eq!(com(6, 0), 1); - assert_eq!(com(6, 1), 6); - assert_eq!(com(6, 2), 15); - assert_eq!(com(6, 3), 20); - assert_eq!(com(6, 4), 15); - assert_eq!(com(6, 5), 6); - assert_eq!(com(6, 6), 1); - } -} diff --git a/src/math/eratosthenes.rs b/src/math/eratosthenes.rs deleted file mode 100644 index 6ab7ace..0000000 --- a/src/math/eratosthenes.rs +++ /dev/null @@ -1,38 +0,0 @@ -pub fn eratosthenes_sieve(n: usize) -> Vec { - let mut s = vec![true; n]; - s[0] = false; - s[1] = false; - - for i in 2..n { - if i * i > n { - break; - } - if s[i] { - for k in 2..(n + i - 1) / i { - s[k * i] = false - } - } - } - - s -} - -#[cfg(test)] -mod test_eratosthenes_sieve { - use crate::math::eratosthenes::eratosthenes_sieve; - - #[test] - fn it_works() { - let primes = eratosthenes_sieve(10); - - assert!(!primes[1]); - assert!(primes[2]); - assert!(primes[3]); - assert!(!primes[4]); - assert!(primes[5]); - assert!(!primes[6]); - assert!(primes[7]); - assert!(!primes[8]); - assert!(!primes[9]); - } -} diff --git a/src/math/gcd.rs b/src/math/gcd.rs deleted file mode 100644 index f1465c4..0000000 --- a/src/math/gcd.rs +++ /dev/null @@ -1,20 +0,0 @@ -pub fn gcd(a: i64, b: i64) -> i64 { - if b == 0 { - a - } else { - gcd(b, a % b) - } -} - -#[cfg(test)] -mod test_gcd { - use crate::math::gcd::gcd; - - #[test] - fn it_works() { - assert_eq!(gcd(15, 5), 5); - assert_eq!(gcd(5, 15), 5); - assert_eq!(gcd(198, 26), 2); - assert_eq!(gcd(26, 198), 2); - } -} diff --git a/src/math/mod.rs b/src/math/mod.rs deleted file mode 100644 index c9afdef..0000000 --- a/src/math/mod.rs +++ /dev/null @@ -1,7 +0,0 @@ -pub mod com; -pub mod eratosthenes; -pub mod gcd; -pub mod modcom; -pub mod modinv; -pub mod modpow; -pub mod prime_factorization; diff --git a/src/math/modcom.rs b/src/math/modcom.rs deleted file mode 100644 index 377e650..0000000 --- a/src/math/modcom.rs +++ /dev/null @@ -1,43 +0,0 @@ -pub fn modcom(n: usize, k: usize, div: usize) -> usize { - let mut fact = Vec::::new(); - let mut inv = Vec::::new(); - let mut finv = Vec::::new(); - - let upper = n + 1; - - fact.resize(upper, 0); - inv.resize(upper, 0); - finv.resize(upper, 0); - - fact[0] = 1; - fact[1] = 1; - - finv[0] = 1; - finv[1] = 1; - - inv[1] = 1; - - for i in 2..upper { - fact[i] = fact[i - 1] * i % div; - inv[i] = div - inv[div % i] * (div / i) % div; - finv[i] = finv[i - 1] * inv[i] % div; - } - - fact[n] * (finv[k] * finv[n - k] % div) % div -} - -#[cfg(test)] -mod test_combination { - use crate::math::modcom::modcom; - - #[test] - fn it_works() { - assert_eq!(modcom(6, 0, 7), 1); - assert_eq!(modcom(6, 1, 7), 6); - assert_eq!(modcom(6, 2, 7), 1); - assert_eq!(modcom(6, 3, 7), 6); - assert_eq!(modcom(6, 4, 7), 1); - assert_eq!(modcom(6, 5, 7), 6); - assert_eq!(modcom(6, 6, 7), 1); - } -} diff --git a/src/math/modinv.rs b/src/math/modinv.rs deleted file mode 100644 index 5b915d4..0000000 --- a/src/math/modinv.rs +++ /dev/null @@ -1,59 +0,0 @@ -use crate::math::modpow::modpow; - -pub fn phi(mut n: usize) -> usize { - let mut res = n; - - let mut i = 2; - while i * i <= n { - if n % i == 0 { - res = res / i * (i - 1); - while n % i == 0 { - n /= i; - } - } - i += 1; - } - - if n != 1 { - res = res / n * (n - 1); - } - - res -} - -pub fn modinv(a: usize, p: usize) -> usize { - let m = phi(p); - modpow(a, m - 1, p) -} - -#[cfg(test)] -mod test_modinv { - use crate::math::modinv::modinv; - use crate::math::modpow::modpow; - - fn inv_euler(a: usize, p: usize) -> usize { - modpow(a, p - 2, p) - } - - fn inv_simple(a: usize, p: usize) -> usize { - let mut ret = 1; - loop { - if (a * ret) % p == 1 { - return ret; - } - ret += 1; - } - } - - #[test] - fn it_works_prime() { - // 10^-1 mod 7 - assert_eq!(modinv(10, 7), inv_euler(10, 7)); - } - - #[test] - fn it_works_composite() { - // 10^-1 mod 2019 - assert_eq!(modinv(10, 2019), inv_simple(10, 2019)); - } -} diff --git a/src/math/modpow.rs b/src/math/modpow.rs deleted file mode 100644 index f93c962..0000000 --- a/src/math/modpow.rs +++ /dev/null @@ -1,28 +0,0 @@ -pub fn modpow(mut a: usize, mut n: usize, m: usize) -> usize { - let mut ans = 1; - - while n > 0 { - if n & 1 == 1 { - ans = ans * a % m; - } - - a = a * a % m; - n >>= 1; - } - - ans -} - -#[cfg(test)] -mod test_modpow { - use crate::math::modpow::modpow; - - #[test] - fn it_works() { - assert_eq!(modpow(2, 10, 1_000_000_007), 1024); - assert_eq!(modpow(2, 3, 1_000_000_007), 8); - assert_eq!(modpow(5, 8, 1_000_000_007), 390625); - assert_eq!(modpow(2, 2, 3), 1); - assert_eq!(modpow(2, 3, 3), 2); - } -} diff --git a/src/math/prime_factorization.rs b/src/math/prime_factorization.rs deleted file mode 100644 index b06be9f..0000000 --- a/src/math/prime_factorization.rs +++ /dev/null @@ -1,90 +0,0 @@ -#[derive(Debug, Clone)] -pub struct SequentialPrimeFactorization { - smallest_prime_factors: Vec, -} - -impl SequentialPrimeFactorization { - pub fn new(n: usize) -> Self { - let mut smallest_prime_factors: Vec = (0..=(n + 1)).collect(); - let mut i = 2; - - while i * i <= n { - if smallest_prime_factors[i] == i { - let mut j = i; - while j * i <= n { - smallest_prime_factors[j * i] = i; - j += 1; - } - } - - i += 1; - } - - Self { - smallest_prime_factors, - } - } - - pub fn factorize(&self, mut x: usize) -> Vec { - let mut ret: Vec = vec![]; - while x != 1 { - ret.push(self.smallest_prime_factors[x]); - x /= self.smallest_prime_factors[x]; - } - - ret.sort_unstable(); - ret - } -} - -pub fn prime_factorize(mut n: usize) -> Vec<(usize, usize)> { - let mut ret = vec![]; - let mut p = 2; - - while p * p <= n { - if n % p == 0 { - let mut k = 0; - while n % p == 0 { - k += 1; - n /= p; - } - ret.push((p, k)); - } - - p += 1; - } - - if n != 1 { - ret.push((n, 1)); - } - ret -} - -#[cfg(test)] -mod test_prime_factorization { - use crate::math::prime_factorization::prime_factorize; - use crate::math::prime_factorization::SequentialPrimeFactorization; - - #[test] - fn it_works_sequential_prime_factorization() { - let prime_factorizer = SequentialPrimeFactorization::new(100); - - assert_eq!(prime_factorizer.factorize(1), vec![]); - assert_eq!(prime_factorizer.factorize(2), vec![2]); - assert_eq!(prime_factorizer.factorize(4), vec![2, 2]); - assert_eq!(prime_factorizer.factorize(7), vec![7]); - assert_eq!(prime_factorizer.factorize(30), vec![2, 3, 5]); - assert_eq!(prime_factorizer.factorize(23), vec![23]); - } - - #[test] - fn it_works_prime_factorization() { - assert_eq!(prime_factorize(1), vec![]); - assert_eq!(prime_factorize(2), vec![(2, 1)]); - assert_eq!(prime_factorize(4), vec![(2, 2)]); - assert_eq!(prime_factorize(7), vec![(7, 1)]); - assert_eq!(prime_factorize(30), vec![(2, 1), (3, 1), (5, 1)]); - assert_eq!(prime_factorize(23), vec![(23, 1)]); - assert_eq!(prime_factorize(512), vec![(2, 9)]); - } -} diff --git a/src/search/lower_bound.rs b/src/search.rs similarity index 52% rename from src/search/lower_bound.rs rename to src/search.rs index 8c36b47..38e6247 100644 --- a/src/search/lower_bound.rs +++ b/src/search.rs @@ -22,7 +22,7 @@ pub fn lower_bound(range: std::ops::Range, prop: &dyn Fn(usize) -> bool) #[cfg(test)] mod test_lower_bound { - use crate::search::lower_bound::lower_bound; + use crate::search::lower_bound; #[test] fn it_works() { @@ -35,3 +35,37 @@ mod test_lower_bound { assert_eq!(lower_bound(0..vs.len(), &|x| 100 <= vs[x]), None); } } + +pub fn upper_bound(range: std::ops::Range, prop: &dyn Fn(usize) -> bool) -> Option { + if !prop(range.start) { + return None; + } + + let mut ok = range.start; + let mut ng = range.end; + + while ng - ok > 1 { + let middle = ok + (ng - ok) / 2; + match prop(middle) { + true => ok = middle, + false => ng = middle, + } + } + + Some(ok) +} + +#[cfg(test)] +mod test_upper_bound { + use crate::search::upper_bound; + + #[test] + fn it_works() { + let vs: Vec = vec![1, 2, 3, 5, 7, 10]; + assert_eq!(upper_bound(0..vs.len(), &|x| vs[x] < 1), None); + assert_eq!(upper_bound(0..vs.len(), &|x| vs[x] < 2), Some(0)); + assert_eq!(upper_bound(0..vs.len(), &|x| vs[x] < 3), Some(1)); + assert_eq!(upper_bound(0..vs.len(), &|x| vs[x] < 7), Some(3)); + assert_eq!(upper_bound(0..vs.len(), &|x| vs[x] < 10), Some(4)); + } +} diff --git a/src/search/mod.rs b/src/search/mod.rs deleted file mode 100644 index 4356800..0000000 --- a/src/search/mod.rs +++ /dev/null @@ -1,2 +0,0 @@ -pub mod lower_bound; -pub mod upper_bound; diff --git a/src/search/upper_bound.rs b/src/search/upper_bound.rs deleted file mode 100644 index 44d4406..0000000 --- a/src/search/upper_bound.rs +++ /dev/null @@ -1,33 +0,0 @@ -pub fn upper_bound(range: std::ops::Range, prop: &dyn Fn(usize) -> bool) -> Option { - if !prop(range.start) { - return None; - } - - let mut ok = range.start; - let mut ng = range.end; - - while ng - ok > 1 { - let middle = ok + (ng - ok) / 2; - match prop(middle) { - true => ok = middle, - false => ng = middle, - } - } - - Some(ok) -} - -#[cfg(test)] -mod test_upper_bound { - use crate::search::upper_bound::upper_bound; - - #[test] - fn it_works() { - let vs: Vec = vec![1, 2, 3, 5, 7, 10]; - assert_eq!(upper_bound(0..vs.len(), &|x| vs[x] < 1), None); - assert_eq!(upper_bound(0..vs.len(), &|x| vs[x] < 2), Some(0)); - assert_eq!(upper_bound(0..vs.len(), &|x| vs[x] < 3), Some(1)); - assert_eq!(upper_bound(0..vs.len(), &|x| vs[x] < 7), Some(3)); - assert_eq!(upper_bound(0..vs.len(), &|x| vs[x] < 10), Some(4)); - } -} diff --git a/src/string/z.rs b/src/string.rs similarity index 96% rename from src/string/z.rs rename to src/string.rs index a0a6a87..b214f57 100644 --- a/src/string/z.rs +++ b/src/string.rs @@ -35,7 +35,7 @@ pub fn z(s: &str) -> Vec { #[cfg(test)] mod test_z_algorithm { - use crate::string::z::z; + use crate::string::z; #[test] fn it_works() { diff --git a/src/string/mod.rs b/src/string/mod.rs deleted file mode 100644 index eb603f6..0000000 --- a/src/string/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod z; diff --git a/src/tree/segment_tree.rs b/src/tree.rs similarity index 98% rename from src/tree/segment_tree.rs rename to src/tree.rs index 008a8d4..7d22498 100644 --- a/src/tree/segment_tree.rs +++ b/src/tree.rs @@ -193,9 +193,9 @@ impl SegmentTree { #[cfg(test)] mod test_segment_tree { - use crate::tree::segment_tree::Mode; - use crate::tree::segment_tree::Op; - use crate::tree::segment_tree::SegmentTree; + use crate::tree::Mode; + use crate::tree::Op; + use crate::tree::SegmentTree; #[test] fn it_works_raq() { diff --git a/src/tree/lib.rs b/src/tree/lib.rs deleted file mode 100644 index 657b92c..0000000 --- a/src/tree/lib.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod segment_tree; diff --git a/src/tree/mod.rs b/src/tree/mod.rs deleted file mode 100644 index 657b92c..0000000 --- a/src/tree/mod.rs +++ /dev/null @@ -1 +0,0 @@ -pub mod segment_tree;