competitive/tree/
generator.rs1use super::{RandomSpec, UndirectedSparseGraph, Xorshift};
2
3pub struct PruferSequence<T>(pub T);
5
6impl<T: RandomSpec<usize>> RandomSpec<UndirectedSparseGraph> for PruferSequence<T> {
7 fn rand(&self, rng: &mut Xorshift) -> UndirectedSparseGraph {
8 let n = rng.random(&self.0);
9 let edges = from_prufer_sequence(
10 n,
11 &rng.random_iter(0..n)
12 .take(n.saturating_sub(2))
13 .collect::<Vec<usize>>(),
14 );
15 UndirectedSparseGraph::from_edges(n, edges)
16 }
17}
18
19pub struct PathTree<T>(pub T);
20
21impl<T: RandomSpec<usize>> RandomSpec<UndirectedSparseGraph> for PathTree<T> {
22 fn rand(&self, rng: &mut Xorshift) -> UndirectedSparseGraph {
23 let n = rng.random(&self.0);
24 let edges = (1..n).map(|u| (u - 1, u)).collect();
25 UndirectedSparseGraph::from_edges(n, edges)
26 }
27}
28
29pub struct StarTree<T>(pub T);
30
31impl<T: RandomSpec<usize>> RandomSpec<UndirectedSparseGraph> for StarTree<T> {
32 fn rand(&self, rng: &mut Xorshift) -> UndirectedSparseGraph {
33 let n = rng.random(&self.0);
34 let edges = (1..n).map(|u| (0, u)).collect();
35 UndirectedSparseGraph::from_edges(n, edges)
36 }
37}
38
39pub struct MixedTree<T>(pub T);
40
41impl<T: RandomSpec<usize>> RandomSpec<UndirectedSparseGraph> for MixedTree<T> {
42 fn rand(&self, rng: &mut Xorshift) -> UndirectedSparseGraph {
43 fn rand_inner(n: usize, rng: &mut Xorshift) -> Vec<(usize, usize)> {
44 let mut edges = Vec::with_capacity(n.saturating_sub(1));
45 if n >= 2 {
46 let k = rng.random(1..n);
47 for n in [k, n - k].iter().cloned() {
48 let ty = rng.rand(6);
49 edges.extend(match ty {
50 0 => from_prufer_sequence(
51 n,
52 &rng.random_iter(0..n)
53 .take(n.saturating_sub(2))
54 .collect::<Vec<usize>>(),
55 ),
56 1 => (1..n).map(|u| (u - 1, u)).collect(),
57 2 => (1..n).map(|u| (0, u)).collect(),
58 _ => rand_inner(n, rng),
59 });
60 }
61 for (u, v) in edges[k - 1..].iter_mut() {
62 *u += k;
63 *v += k;
64 }
65 edges.push((rng.random(0..k), rng.random(k..n)));
66 }
67 edges
68 }
69 let n = rng.random(&self.0);
70 let edges = rand_inner(n, rng);
71 UndirectedSparseGraph::from_edges(n, edges)
72 }
73}
74
75fn from_prufer_sequence(n: usize, prufer: &[usize]) -> Vec<(usize, usize)> {
76 use std::collections::BinaryHeap;
77 let mut edges = Vec::with_capacity(n.saturating_sub(1));
78 if n >= 2 {
79 let mut deg = vec![0usize; n];
80 prufer.iter().for_each(|&a| deg[a] += 1);
81 let mut heap: BinaryHeap<usize> = (0..n).filter(|&u| deg[u] == 0).collect();
82 for &a in prufer {
83 deg[a] -= 1;
84 let b = heap.pop().unwrap();
85 edges.push((a, b));
86 if deg[a] == 0 {
87 heap.push(a);
88 }
89 }
90 edges.push((heap.pop().unwrap(), heap.pop().unwrap()));
91 }
92 edges
93}
94
95#[cfg(test)]
96mod tests {
97 use super::*;
98
99 fn is_connected(g: &UndirectedSparseGraph) -> bool {
100 let n = g.vertices_size();
101 if n == 0 {
102 return true;
103 }
104 let mut vis = vec![false; n];
105 let mut stack = vec![0];
106 let mut acc = 0usize;
107 vis[0] = true;
108 while let Some(u) = stack.pop() {
109 acc += 1;
110 for a in g.adjacencies(u) {
111 if !vis[a.to] {
112 vis[a.to] = true;
113 stack.push(a.to);
114 }
115 }
116 }
117 acc == n
118 }
119
120 fn is_tree(g: &UndirectedSparseGraph) -> bool {
121 let n = g.vertices_size();
122 let m = g.edges_size();
123 (n == 0 || m + 1 == n) && is_connected(g)
124 }
125
126 #[test]
127 fn prufer_sequence_small() {
128 const Q: usize = 10_000;
129 const N: usize = 20;
130 let mut rng = Xorshift::default();
131 for _ in 0..Q {
132 let g = rng.random(PruferSequence(1..=N));
133 assert!(is_tree(&g));
134 }
135 }
136
137 #[test]
138 fn prufer_sequence_big() {
139 const Q: usize = 20;
140 const N: usize = 10_000;
141 let mut rng = Xorshift::default();
142 for _ in 0..Q {
143 let g = rng.random(PruferSequence(N - Q..=N));
144 assert!(is_tree(&g));
145 }
146 }
147
148 #[test]
149 fn path_small() {
150 const N: usize = 20;
151 let mut rng = Xorshift::default();
152 for n in 0..=N {
153 let g = rng.random(PathTree(n));
154 assert!(is_tree(&g));
155 }
156 }
157
158 #[test]
159 fn path_big() {
160 const Q: usize = 20;
161 const N: usize = 10_000;
162 let mut rng = Xorshift::default();
163 for n in N - Q..=N {
164 let g = rng.random(PathTree(n));
165 assert!(is_tree(&g));
166 }
167 }
168
169 #[test]
170 fn star_small() {
171 const N: usize = 20;
172 let mut rng = Xorshift::default();
173 for n in 0..=N {
174 let g = rng.random(StarTree(n));
175 assert!(is_tree(&g));
176 }
177 }
178
179 #[test]
180 fn star_big() {
181 const Q: usize = 20;
182 const N: usize = 10_000;
183 let mut rng = Xorshift::default();
184 for n in N - Q..=N {
185 let g = rng.random(StarTree(n));
186 assert!(is_tree(&g));
187 }
188 }
189
190 #[test]
191 fn mixed_small() {
192 const Q: usize = 10_000;
193 const N: usize = 20;
194 let mut rng = Xorshift::default();
195 for _ in 0..Q {
196 let g = rng.random(MixedTree(1..=N));
197 assert!(is_tree(&g));
198 }
199 }
200
201 #[test]
202 fn mixed_big() {
203 const Q: usize = 20;
204 const N: usize = 10_000;
205 let mut rng = Xorshift::default();
206 for _ in 0..Q {
207 let g = rng.random(MixedTree(N - Q..=N));
208 assert!(is_tree(&g));
209 }
210 }
211}