From 0d103dcd9d60174981db57af37b61fa445505032 Mon Sep 17 00:00:00 2001 From: Franz Diebold Date: Thu, 3 Oct 2019 12:11:04 +0200 Subject: [PATCH] Add solution for problem 23. --- README.md | 2 +- src/common/divisors.py | 54 +++++++++++++++++++++++++++++++ src/p021_amicable_numbers.py | 20 +----------- src/p023_non_abundant_sums.py | 61 +++++++++++++++++++++++++++++++++++ 4 files changed, 117 insertions(+), 20 deletions(-) create mode 100644 src/common/divisors.py create mode 100644 src/p023_non_abundant_sums.py diff --git a/README.md b/README.md index 563f1b2..111c682 100644 --- a/README.md +++ b/README.md @@ -1,6 +1,6 @@ # [Project Euler](https://projecteuler.net) Solutions -[![solved: 22 problems](https://img.shields.io/badge/solved-22_problems-f93.svg)](./src) +[![solved: 23 problems](https://img.shields.io/badge/solved-23_problems-f93.svg)](./src) ![Python: 3.7](https://img.shields.io/badge/Python-3.7-3776ab.svg) [![Build Status](https://travis-ci.com/FranzDiebold/project-euler-solutions.svg?branch=master)](https://travis-ci.com/FranzDiebold/project-euler-solutions) [![license: MIT](https://img.shields.io/badge/license-MIT-brightgreen.svg)](./LICENSE.md) diff --git a/src/common/divisors.py b/src/common/divisors.py new file mode 100644 index 0000000..66162b9 --- /dev/null +++ b/src/common/divisors.py @@ -0,0 +1,54 @@ +""" +Proper divisor utility functions. +""" + +from typing import Iterable +import math + + +def divisors(number: int) -> Iterable[int]: + """Get proper divisors for given number `number`. + + Example: + 220 -> [1, 2, 4, 5, 10, 11, 20, 22, 44, 55, 110] + The numbers may be in a random order. + """ + yield 1 + for i in range(2, math.floor(math.sqrt(number)) + 1): + if number % i == 0: + yield i + if i**2 < number: + yield number // i + + +def get_sum_of_divisors(number: int) -> int: + """Get sum of proper divisors of number `number`.""" + return sum(divisors(number)) + + +def is_perferct_number(number: int) -> bool: + """Check if a given number `number` is a perfect number. + + 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. + """ + return get_sum_of_divisors(number) == number + + +def is_deficient_number(number: int) -> bool: + """Check if a given number `number` is a deficient number. + + A number n is called deficient if the sum of its proper divisors is less than n. + """ + return get_sum_of_divisors(number) < number + + +def is_abundant_number(number: int) -> bool: + """Check if a given number `number` is a abundant number. + + A number n is called abundant if the sum of its proper divisors exceeds n. + """ + return get_sum_of_divisors(number) > number diff --git a/src/p021_amicable_numbers.py b/src/p021_amicable_numbers.py index a81fb10..090b319 100644 --- a/src/p021_amicable_numbers.py +++ b/src/p021_amicable_numbers.py @@ -15,26 +15,8 @@ """ from typing import Iterable, Tuple -import math - -def divisors(number: int) -> Iterable[int]: - """Get proper divisors for given number `number`. - - Example: - 220 -> [1, 2, 4, 5, 10, 11, 20, 22, 44, 55, 110] - The numbers may be in a random order. - """ - yield 1 - for i in range(2, math.floor(math.sqrt(number))): - if number % i == 0: - yield i - yield number // i - - -def get_sum_of_divisors(number: int) -> int: - """Get sum of proper divisors of number `number`.""" - return sum(divisors(number)) +from src.common.divisors import get_sum_of_divisors def get_amicable_pairs(threshold: int) -> Iterable[Tuple[int, int]]: diff --git a/src/p023_non_abundant_sums.py b/src/p023_non_abundant_sums.py new file mode 100644 index 0000000..f87dd6a --- /dev/null +++ b/src/p023_non_abundant_sums.py @@ -0,0 +1,61 @@ +""" +Problem 23: Non-abundant sums +https://projecteuler.net/problem=23 + +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. + +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. + +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. + +Find the sum of all the positive integers +which cannot be written as the sum of two abundant numbers. +""" + +from typing import Set + +from src.common.divisors import is_abundant_number + + +def get_abundant_numbers(threshold: int) -> Set[int]: + """Get set of abundant numbers below given threshold `threshold'.""" + abundant_numbers = set() + for i in range(1, threshold + 1): + if is_abundant_number(i): + abundant_numbers.add(i) + return abundant_numbers + + +def is_sum_of_numbers(number: int, numbers: Set[int]) -> bool: + """Check if a given number `number` is the sum of any two numbers from `numbers`.""" + for i in range(1, number): + if i in numbers and (number - i) in numbers: + return True + return False + + +def main() -> None: + """Main function.""" + threshold = 28123 + total_sum = 0 + abundant_numbers = get_abundant_numbers(threshold) + for i in range(1, threshold + 1): + if not is_sum_of_numbers(i, abundant_numbers): + total_sum += i + print(f'The sum of all the positive integers which cannot be written as the sum ' \ + f'of two abundant numbers is {total_sum:,}.') + + +if __name__ == '__main__': + main()