add 23
This commit is contained in:
@@ -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"
|
||||||
@@ -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);
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user