use crate::Solution;
use std::collections::HashMap;
problem!(Problem0061, 61, "Cyclical Figurate Numbers");
impl Solution for Problem0061 {
fn solve(&self) -> String {
let triangle = generate_numbers(
|| {
let first_n = ((-1.0 + (1.0f64 - 4.0 * 1.0 * -2.0 * MIN_4_DIGIT as f64).sqrt())
/ 2.0)
.ceil() as u16;
let first_value = first_n * (first_n + 1) / 2;
(first_n, first_value)
},
|n, value| value + n + 1,
);
let square = generate_numbers(
|| {
let first_n = (MIN_4_DIGIT as f64).sqrt().ceil() as u16;
let first_value = first_n * first_n;
(first_n, first_value)
},
|n, value| value + 2 * n + 1,
);
let pentagonal = generate_numbers(
|| {
let first_n = ((1.0 + (1.0f64 - 4.0 * 3.0 * -2.0 * MIN_4_DIGIT as f64).sqrt())
/ 6.0)
.ceil() as u16;
let first_value = first_n * (3 * first_n - 1) / 2;
(first_n, first_value)
},
|n, value| value + 3 * n + 1,
);
let hexagonal = generate_numbers(
|| {
let first_n = ((1.0 + (1.0f64 - 4.0 * 2.0 * -(MIN_4_DIGIT as f64)).sqrt()) / 4.0)
.ceil() as u16;
let first_value = first_n * (2 * first_n - 1);
(first_n, first_value)
},
|n, value| value + 4 * n + 1,
);
let heptagonal = generate_numbers(
|| {
let first_n = ((3.0 + (9.0f64 - 4.0 * 5.0 * -2.0 * MIN_4_DIGIT as f64).sqrt())
/ 10.0)
.ceil() as u16;
let first_value = first_n * (5 * first_n - 3) / 2;
(first_n, first_value)
},
|n, value| value + 5 * n + 1,
);
let octagonal = generate_numbers(
|| {
let first_n = ((2.0 + (4.0f64 - 4.0 * 3.0 * -(MIN_4_DIGIT as f64)).sqrt()) / 6.0)
.ceil() as u16;
let first_value = first_n * (3 * first_n - 2);
(first_n, first_value)
},
|n, value| value + 6 * n + 1,
);
let square_map = generate_map(&square);
let pentagonal_map = generate_map(&pentagonal);
let hexagonal_map = generate_map(&hexagonal);
let heptagonal_map = generate_map(&heptagonal);
let octagonal_map = generate_map(&octagonal);
let maps = [
&square_map,
&pentagonal_map,
&hexagonal_map,
&heptagonal_map,
&octagonal_map,
];
let mut visited_maps = [false; 5];
let mut stack = Vec::with_capacity(6);
for n in triangle {
stack.push(n);
if rec(&mut stack, &maps, &mut visited_maps) {
break;
}
stack.pop();
}
stack.into_iter().map(|n| n as u32).sum::<u32>().to_string()
}
}
const MIN_4_DIGIT: u16 = 1000;
const MAX_4_DIGIT: u16 = 9999;
fn rec(stack: &mut Vec<u16>, maps: &[&HashMap<u16, Vec<u16>>], visited_maps: &mut [bool]) -> bool {
if stack.len() == 6 {
return stack.last().unwrap() % 100 == stack[0] / 100;
}
for i in 0..5 {
if !visited_maps[i]
&& let Some(next_values) = maps[i].get(&(stack.last().unwrap() % 100))
{
visited_maps[i] = true;
for next_value in next_values {
stack.push(*next_value);
if rec(stack, maps, visited_maps) {
return true;
}
stack.pop();
}
visited_maps[i] = false;
}
}
false
}
fn generate_map(nums: &[u16]) -> HashMap<u16, Vec<u16>> {
let mut map: HashMap<u16, Vec<u16>> = HashMap::new();
for &num in nums {
let key = num / 100;
if let Some(vec) = map.get_mut(&key) {
vec.push(num);
} else {
map.insert(key, vec![num]);
}
}
map
}
fn generate_numbers<T, U>(first: T, next: U) -> Vec<u16>
where
T: Fn() -> (u16, u16),
U: Fn(u16, u16) -> u16,
{
let mut numbers = Vec::new();
let (n, mut value) = first();
numbers.push(value);
for n in n.. {
value = next(n, value);
if value > MAX_4_DIGIT {
break;
}
numbers.push(value);
}
numbers
}