scarlet_queen_entrypoint/
find_cycle.rs1use std::{collections::HashMap, hash::Hash, io::Write};
2
3pub fn find_tail_cycle<T, W>(
4 count_data: &[HashMap<T, usize>],
5 out: &mut W,
6) -> Result<(), std::io::Error>
7where
8 T: Clone + Eq + Hash,
9 W: Write,
10{
11 let data_len: usize = count_data.len();
12 let (header_len, cycle_len) = tail_cycle(count_data);
13 let result: String = if let Some(v) = count_data.last() {
14 let mut last_count: Vec<&usize> = v.values().collect::<Vec<&usize>>();
15 last_count.sort();
16 if last_count
17 .iter()
18 .take(last_count.len() - 1)
19 .all(|&&v| v == 0)
20 {
21 "cycle: Divergence".to_string()
22 } else if header_len == data_len {
23 "cycle: NotEnoughLoop".to_string()
24 } else {
25 format!("cycle: HeaderLen-CycleLen({header_len}-{cycle_len})")
26 }
27 } else {
28 "cycle: NoData".to_string()
29 };
30 writeln!(out, "{result}")
31}
32
33pub fn tail_cycle<T>(data: &[T]) -> (usize, usize)
34where
35 T: Eq,
36{
37 let data_len: usize = data.len();
38 let data_rev: Vec<&T> = data.iter().rev().collect::<Vec<&T>>();
39 let match_table: Vec<usize> = match_table(data_rev);
40 match_table
41 .iter()
42 .copied()
43 .enumerate()
44 .skip(1)
45 .zip(match_table.iter().copied())
46 .filter_map(|((i, u), v)| {
47 if u == v + 1 && (i - u) * 2 <= i {
48 Some((i, i - u))
49 } else {
50 None
51 }
52 })
53 .next_back()
54 .map(|(all_cycle_len, cycle_len)| (data_len - all_cycle_len, cycle_len))
55 .unwrap_or((data_len, 0))
56}
57
58fn match_table<T>(data: Vec<&T>) -> Vec<usize>
59where
60 T: Eq,
61{
62 if data.len() <= 2 {
63 return vec![0; data.len()];
64 }
65 let mut res: Vec<usize> = vec![0; data.len()];
66 'a: for i in 1..(data.len() - 1) {
67 let mut j: usize = i;
68 while data[i] != data[res[j]] {
69 j = res[j];
70 if j == 0 {
71 res[i + 1] = 0;
72 continue 'a;
73 }
74 }
75 res[i + 1] = res[j] + 1;
76 }
77 res
78}