From 5cb8d0cfe7321dbea5befc34261ccab5785e9859 Mon Sep 17 00:00:00 2001 From: "Dr. Matthias Ratajczak" Date: Wed, 28 Jun 2023 14:41:10 +0200 Subject: [PATCH] basic version of 95, very slow --- src/euler95/Cargo.toml | 7 ++- src/euler95/src/main.rs | 117 +++++++++++++++++++++++++++------------- 2 files changed, 86 insertions(+), 38 deletions(-) diff --git a/src/euler95/Cargo.toml b/src/euler95/Cargo.toml index 38eb5dd..269262f 100644 --- a/src/euler95/Cargo.toml +++ b/src/euler95/Cargo.toml @@ -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" diff --git a/src/euler95/src/main.rs b/src/euler95/src/main.rs index 0bf37d4..f059047 100644 --- a/src/euler95/src/main.rs +++ b/src/euler95/src/main.rs @@ -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(¤t) { 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>, + part_of_any_chain: &mut HashSet, +) { + 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 { 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) { + use crate::get_proper_divisors; + + assert_eq!(get_proper_divisors(input).collect::>(), 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>) { + 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); + } +}