This commit is contained in:
timeshifter
2025-03-14 18:56:20 +01:00
parent 5941c2584f
commit ce4565938c
2 changed files with 130 additions and 0 deletions
+11
View File
@@ -0,0 +1,11 @@
[package]
name = "euler23"
version = "0.1.0"
edition = "2024"
[dependencies]
itertools = "0.14.0"
proper_divisors = { version = "*", path = "../../lib/proper_divisors" }
[dev-dependencies]
rstest = "0.25.0"
+119
View File
@@ -0,0 +1,119 @@
use itertools::Itertools;
use proper_divisors::ProperDivisors;
const MIN: usize = 1;
// const MAX: usize = 500;
const MAX: usize = 28_123;
fn main() {
let pd = ProperDivisors::get_between(MIN, MAX);
let abundant_numbers = AbundantNumbers::get_between(MIN, MAX, pd);
// dbg!(abundant_numbers.can_be_sum_of_two_abundant_numbers(24));
let mut sum = 0;
for number in MIN..=MAX {
if !abundant_numbers.can_be_sum_of_two_abundant_numbers(number) {
//println!("{number}");
sum += number;
}
}
println!("{sum}");
}
struct AbundantNumbers(Vec<usize>);
impl AbundantNumbers {
fn get_between(smaller: usize, larger: usize, pd: ProperDivisors) -> Self {
let result = (smaller..=larger)
.filter(|n| Self::is_abundant_number(*n, &pd))
.collect();
Self(result)
}
fn can_be_sum_of_two_abundant_numbers(&self, number: usize) -> bool {
let (mut larger_idx, mut larger) = self.get_closest_abundant_number_and_index(number);
let (mut smaller_idx, mut smaller) = (0, 12);
loop {
if larger < smaller {
break false;
}
let sum = larger + smaller;
if sum == number {
break true;
}
match sum.cmp(&number) {
std::cmp::Ordering::Less => {
smaller_idx += 1;
if let Some(result) = self.0.get(smaller_idx) {
smaller = *result;
} else {
break false;
}
}
std::cmp::Ordering::Equal => (),
std::cmp::Ordering::Greater => {
if larger_idx == 0 {
break false;
}
larger_idx = larger_idx.saturating_sub(1);
larger = self.0[larger_idx];
}
}
}
}
fn get_closest_abundant_number_and_index(&self, number: usize) -> (usize, usize) {
let mut offset = 0;
loop {
let larger = number + offset;
if let Some((index, larger)) = self.0.iter().find_position(|n| **n == larger) {
return (index, *larger);
}
let smaller = number.saturating_sub(offset);
if let Some((index, smaller)) = self.0.iter().find_position(|n| **n == smaller) {
return (index, *smaller);
}
offset += 1;
}
}
fn is_abundant_number(number: usize, pd: &ProperDivisors) -> bool {
pd.get(number).iter().sum::<usize>() > number
}
}
#[cfg(test)]
mod tests {
use proper_divisors::ProperDivisors;
use rstest::rstest;
use crate::{can_be_sum_of_two_abundant_numbers, get_abundant_numbers, is_abundant_number};
#[rstest]
#[case(28, false)]
#[case(12, true)]
fn test_is_abundant_number(#[case] input: usize, #[case] expected: bool) {
let pd = ProperDivisors::get_between(2, input + 1);
let result = is_abundant_number(input, &pd);
assert_eq!(result, expected);
}
#[rstest]
#[case(24, true)]
#[case(23, false)]
fn test_can_be_sum_of_two_abundant_numbers(#[case] input: usize, #[case] expected: bool) {
let pd = ProperDivisors::get_between(2, input + 1);
let abundant_numbers = get_abundant_numbers(pd);
let result = can_be_sum_of_two_abundant_numbers(input, &abundant_numbers);
assert_eq!(result, expected);
}
}