1use std::collections::HashSet;
2
3pub use rand_core;
4
5#[derive(Debug, Clone, PartialEq, Eq, Hash)]
7pub struct Graph(Box<[(u32, u32)]>);
8
9impl Graph {
10 pub fn new(rng: &mut impl rand_core::RngCore, n: u8) -> Self {
18 assert!(n <= 32, "graph n param must be lower or equal to 32");
19
20 let edges_number = 1_usize << n;
21
22 let mut nodes = Vec::with_capacity(edges_number);
23
24 for _ in 0..edges_number {
25 let from_node = rng.next_u32() % edges_number as u32;
26 let to_node = rng.next_u32() % edges_number as u32;
27
28 nodes.push((from_node, to_node));
30 }
31
32 Self(nodes.into_boxed_slice())
33 }
34
35 pub fn solve(
41 &self,
42 max_depth: usize,
43 mut handler: impl FnMut(&[u32]) -> bool
44 ) -> Option<Box<[u32]>> {
45 let edges_number = self.0.len();
46
47 let mut top_nodes = vec![vec![]; edges_number];
49 let mut bottom_nodes = vec![vec![]; edges_number];
50
51 for (top_node, bottom_node) in &self.0 {
52 if !top_nodes[*top_node as usize].contains(bottom_node) {
53 top_nodes[*top_node as usize].push(*bottom_node);
54 }
55
56 if !bottom_nodes[*bottom_node as usize].contains(top_node) {
57 bottom_nodes[*bottom_node as usize].push(*top_node);
58 }
59 }
60
61 #[allow(clippy::needless_range_loop)]
63 for top_node in 0..edges_number {
64 if top_nodes[top_node].len() < 2 {
65 for bottom_node in &top_nodes[top_node] {
66 bottom_nodes[*bottom_node as usize].retain(|node| {
67 node != &(top_node as u32)
68 });
69 }
70
71 top_nodes[top_node].clear();
72 }
73 }
74
75 #[allow(clippy::needless_range_loop)]
77 for bottom_node in 0..edges_number {
78 if bottom_nodes[bottom_node].len() < 2 {
79 for top_node in &bottom_nodes[bottom_node] {
80 top_nodes[*top_node as usize].retain(|node| {
81 node != &(bottom_node as u32)
82 });
83 }
84
85 bottom_nodes[bottom_node].clear();
86 }
87 }
88
89 #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
91 enum GraphSide {
92 Top(u32),
93 Bottom(u32)
94 }
95
96 for target_top_node in 0..edges_number as u32 {
97 if top_nodes[target_top_node as usize].is_empty() {
98 continue;
99 }
100
101 let mut stack: Vec<(GraphSide, Box<[u32]>)> = Vec::new();
102 let mut visited = HashSet::new();
103
104 stack.push((
105 GraphSide::Top(target_top_node),
106 Box::new([target_top_node])
107 ));
108
109 while let Some((node, path)) = stack.pop() {
110 if visited.insert(node) && path.len() < max_depth {
111 match node {
112 GraphSide::Top(top_node) => {
113 for bottom_node in &top_nodes[top_node as usize] {
114 let mut path = path.to_vec();
115
116 path.push(*bottom_node);
117
118 stack.push((
119 GraphSide::Bottom(*bottom_node),
120 path.into_boxed_slice()
121 ));
122 }
123 }
124
125 GraphSide::Bottom(bottom_node) => {
126 for top_node in &bottom_nodes[bottom_node as usize] {
127 let mut path = path.to_vec();
128
129 path.push(*top_node);
130
131 stack.push((
132 GraphSide::Top(*top_node),
133 path.into_boxed_slice()
134 ));
135 }
136 }
137 }
138 }
139
140 else if node == GraphSide::Top(target_top_node)
141 && path.len() > 3
142 && handler(&path)
143 {
144 return Some(path);
145 }
146 }
147 }
148
149 None
150 }
151
152 pub fn solve_for(&self, diff: usize)-> Option<Box<[u32]>> {
158 if diff % 2 == 0 || diff < 5 {
159 return None;
160 }
161
162 self.solve(diff, |cycle| cycle.len() == diff)
163 }
164
165 pub fn verify(&self, cycle: &[u32]) -> bool {
167 let n = cycle.len();
168
169 if n % 2 == 0 {
171 return false;
172 }
173
174 let mut i = 1;
175
176 while i < n {
177 let mut found = false;
178
179 for (top_node, bottom_node) in &self.0 {
180 if (i % 2 != 0 && top_node == &cycle[i - 1] && bottom_node == &cycle[i])
181 || (i % 2 == 0 && bottom_node == &cycle[i - 1] && top_node == &cycle[i])
182 {
183 found = true;
184
185 break;
186 }
187 }
188
189 if !found {
190 return false;
191 }
192
193 i += 1;
194 }
195
196 true
197 }
198}
199
200#[test]
201fn test() {
202 use rand_core::SeedableRng;
203
204 let mut rng = rand_chacha::ChaCha8Rng::seed_from_u64(123);
205
206 let graph = Graph::new(&mut rng, 16);
207
208 assert!(graph.solve_for(9).is_some());
209
210 assert!(graph.verify(&[
211 1981,
212 19107,
213 3084,
214 24653,
215 6267,
216 46608,
217 34728,
218 11923,
219 1981
220 ]));
221}