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