basic version of 95, very slow

This commit is contained in:
Dr. Matthias Ratajczak
2023-06-28 14:41:10 +02:00
parent 708aafb362
commit 5cb8d0cfe7
2 changed files with 86 additions and 38 deletions
+6 -1
View File
@@ -5,4 +5,9 @@ edition = "2021"
# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html
[dependencies]
[dev-dependencies]
rstest = "0.17"
[profile.release]
debug = true
lto = "fat"
+80 -37
View File
@@ -1,51 +1,94 @@
const MAX: usize = 1_000;
use std::collections::HashSet;
const MAX: usize = 1_000_000;
fn main() {
let mut numbers: Vec<_> = (0_usize..MAX + 1).map(|_| true).collect();
let mut chains = vec![];
let mut i = 0_usize;
loop {
if i > MAX {
break;
}
let mut num = if numbers[i] {
numbers[i] = false;
i
} else {
i += 1;
let mut part_of_any_chain = HashSet::new();
for current in 1..MAX {
if part_of_any_chain.contains(&current) {
continue;
};
let mut maybe_chain = vec![];
loop {
let next: usize = get_proper_divisors(num).sum();
if next > MAX {
break;
}
if !numbers[next] {
if maybe_chain.contains(&next) {
chains.push(maybe_chain);
}
break;
}
numbers[next] = false;
maybe_chain.push(num);
num = next;
}
i += 1;
try_build_chain_from_number(MAX, current, &mut chains, &mut part_of_any_chain);
}
dbg!(chains);
chains.sort_by_key(|chain| chain.len());
let longest = chains.last().unwrap();
let smallest = longest.iter().min().unwrap().to_owned();
println!("{smallest}");
}
fn try_build_chain_from_number(
max: usize,
mut current: usize,
chains: &mut Vec<Vec<usize>>,
part_of_any_chain: &mut HashSet<usize>,
) {
let mut maybe_chain = vec![];
loop {
maybe_chain.push(current);
let next: usize = get_proper_divisors(current).sum();
if next > max || next == 0 {
break;
}
if maybe_chain.contains(&next) {
if maybe_chain.len() > 1 && *maybe_chain.first().unwrap() == next {
for number in &maybe_chain {
part_of_any_chain.insert(*number);
}
println!("{}", maybe_chain.first().unwrap());
chains.push(maybe_chain);
}
break;
}
current = next;
}
}
fn get_proper_divisors(x: usize) -> impl Iterator<Item = usize> {
let limit = x / 2 + 1;
(1..limit).filter(move |i| x % *i == 0)
}
#[cfg(test)]
mod tests {
use rstest::rstest;
#[rstest]
#[case(6, vec![1, 2, 3])]
#[case(28, vec![1, 2, 4, 7, 14])]
#[case(12_496, vec![1, 2, 4, 8, 11, 16, 22, 44, 71, 88, 142, 176, 284, 568, 781, 1136, 1562, 3124, 6248])]
fn proper_divisor(#[case] input: usize, #[case] expected: Vec<usize>) {
use crate::get_proper_divisors;
assert_eq!(get_proper_divisors(input).collect::<Vec<_>>(), expected);
}
#[rstest]
#[case(220, vec![vec![220, 284]])]
#[case(12_496, vec![vec![12_496, 14_288, 15_472, 14_536, 14_264]])]
fn chain(#[case] input: usize, #[case] expected: Vec<Vec<usize>>) {
use std::collections::HashSet;
use crate::try_build_chain_from_number;
let max = expected.iter().flatten().max().unwrap().to_owned();
let mut part_of_any_chain = HashSet::new();
let mut chains = vec![];
try_build_chain_from_number(max, input, &mut chains, &mut part_of_any_chain);
assert_eq!(chains, expected);
}
}