/* __ __ __ __ __ ___
* \ \ / / \ \ / / __/
* \ \/ / /\ \ \/ / /
* \____/__/ \__\____/__/.ɪᴏ
* ᶜᵒᵖʸʳᶦᵍʰᵗ ᵇʸ ᵛᵃᵛʳ ⁻ ˡᶦᶜᵉⁿˢᵉᵈ ᵘⁿᵈᵉʳ ᵗʰᵉ ᵃᵖᵃᶜʰᵉ ˡᶦᶜᵉⁿˢᵉ ᵛᵉʳˢᶦᵒⁿ ᵗʷᵒ ᵈᵒᵗ ᶻᵉʳᵒ
*/
package io.vavr.collection.euler;
import io.vavr.Function1;
import io.vavr.collection.List;
import io.vavr.collection.Stream;
import org.assertj.core.api.Assertions;
import org.junit.Test;
import static io.vavr.API.*;
import static org.assertj.core.api.Assertions.assertThat;
/**
* <strong>Problem 23: Non-abundant sums</strong>
* <p>
* A perfect number is a number for which the sum of its proper divisors is
* exactly equal to the number. For example, the sum of the proper divisors of
* 28 would be 1 + 2 + 4 + 7 + 14 = 28, which means that 28 is a perfect number.
* <p>
* A number n is called deficient if the sum of its proper divisors is less than
* n and it is called abundant if this sum exceeds n.
* <p>
* As 12 is the smallest abundant number, 1 + 2 + 3 + 4 + 6 = 16, the smallest
* number that can be written as the sum of two abundant numbers is 24. By
* mathematical analysis, it can be shown that all integers greater than 28123
* can be written as the sum of two abundant numbers. However, this upper limit
* cannot be reduced any further by analysis even though it is known that the
* greatest number that cannot be expressed as the sum of two abundant numbers
* is less than this limit.
* <p>
* Find the sum of all the positive integers which cannot be written as the sum
* of two abundant numbers.
* <p>
* See also <a href="https://projecteuler.net/problem=23">projecteuler.net
* problem 23</a>.
*/
public class Euler23Test {
private static final long SMALLEST_ABUNDANT_NUMBER = 12;
private static final long SMALLEST_NUMBER_WRITTEN_AS_THE_SUM_OF_TO_ABUNDANT_NUMBERS = 2 * SMALLEST_ABUNDANT_NUMBER;
private static final long LOWER_LIMIT_FOUND_BY_MATHEMATICAL_ANALYSIS_FOR_NUMBERS_THAT_CAN_BE_WRITTEN_AS_THE_SUM_OF_TO_ABUNDANT_NUMBERS = 28123;
@Test
public void shouldSolveProblem23() {
List.range(1, SMALLEST_ABUNDANT_NUMBER).forEach(n -> Assertions.assertThat(isAbundant.apply(n)).isFalse());
Assertions.assertThat(isAbundant.apply(SMALLEST_ABUNDANT_NUMBER)).isTrue();
Assertions.assertThat(isAbundant.apply(28L)).isFalse();
assertThat(canBeWrittenAsTheSumOfTwoAbundantNumbers(SMALLEST_NUMBER_WRITTEN_AS_THE_SUM_OF_TO_ABUNDANT_NUMBERS - 1)).isFalse();
assertThat(canBeWrittenAsTheSumOfTwoAbundantNumbers(SMALLEST_NUMBER_WRITTEN_AS_THE_SUM_OF_TO_ABUNDANT_NUMBERS)).isTrue();
assertThat(canBeWrittenAsTheSumOfTwoAbundantNumbers(LOWER_LIMIT_FOUND_BY_MATHEMATICAL_ANALYSIS_FOR_NUMBERS_THAT_CAN_BE_WRITTEN_AS_THE_SUM_OF_TO_ABUNDANT_NUMBERS + 1)).isTrue();
assertThat(sumOfAllPositiveIntegersThatCannotBeWrittenAsTheSumOfTwoAbundantNumbers()).isEqualTo(4179871L);
}
private static long sumOfAllPositiveIntegersThatCannotBeWrittenAsTheSumOfTwoAbundantNumbers() {
return Stream.rangeClosed(1, LOWER_LIMIT_FOUND_BY_MATHEMATICAL_ANALYSIS_FOR_NUMBERS_THAT_CAN_BE_WRITTEN_AS_THE_SUM_OF_TO_ABUNDANT_NUMBERS)
.filter(l -> !canBeWrittenAsTheSumOfTwoAbundantNumbers(l))
.sum().longValue();
}
private static boolean canBeWrittenAsTheSumOfTwoAbundantNumbers(long l) {
return Match(l).of(
Case($(n -> n < SMALLEST_NUMBER_WRITTEN_AS_THE_SUM_OF_TO_ABUNDANT_NUMBERS), false),
Case($(SMALLEST_NUMBER_WRITTEN_AS_THE_SUM_OF_TO_ABUNDANT_NUMBERS), true),
Case($(), () -> Stream.rangeClosed(SMALLEST_ABUNDANT_NUMBER, l / 2).exists(a -> isAbundant.apply(a) && isAbundant.apply(l - a)))
);
}
private static final Function1<Long, Boolean> isAbundant = Function1.of((Long l) -> Utils.divisors(l).sum().longValue() > l).memoized();
}