haar_lib/algo/cycle_finding.rs
1//! 循環検出法
2//!
3//! # References
4//! - <https://ja.wikipedia.org/wiki/%E3%83%95%E3%83%AD%E3%82%A4%E3%83%89%E3%81%AE%E5%BE%AA%E7%92%B0%E6%A4%9C%E5%87%BA%E6%B3%95>
5//!
6//! # Problems
7//! - <https://atcoder.jp/contests/abc179/tasks/abc179_e>
8//! - <https://atcoder.jp/contests/typical90/tasks/typical90_bf>
9
10/// [`cycle_finding`]の結果
11#[derive(Clone, Copy, Debug, PartialEq, Eq)]
12pub struct Rho {
13 /// 先頭の非循環部の長さ
14 pub tail: u64,
15 /// 循環部の長さ
16 pub cycle: u64,
17}
18
19/// 循環検出法
20///
21/// **Space complexity** $O(1)$
22pub fn cycle_finding<T>(init: T, f: impl Fn(T) -> T) -> Rho
23where
24 T: Copy + Eq,
25{
26 let mut a = init;
27 let mut b = init;
28 loop {
29 a = f(a);
30 b = f(f(b));
31
32 if a == b {
33 break;
34 }
35 }
36
37 let mut tail = 0;
38 let mut c = init;
39 while a != c {
40 c = f(c);
41 a = f(a);
42 tail += 1;
43 }
44
45 let mut cycle = 0;
46 loop {
47 a = f(a);
48 c = f(f(c));
49 cycle += 1;
50
51 if a == c {
52 break;
53 }
54 }
55
56 Rho { tail, cycle }
57}