diff --git a/DIRECTORY.md b/DIRECTORY.md index 64e9d5333a2f..be5b683398e9 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -632,7 +632,7 @@ ## Physics * [Horizontal Projectile Motion](physics/horizontal_projectile_motion.py) - * [Lorenz Transformation Four Vector](physics/lorenz_transformation_four_vector.py) + * [Lorentz Transformation Four Vector](physics/lorentz_transformation_four_vector.py) * [N Body Simulation](physics/n_body_simulation.py) * [Newtons Second Law Of Motion](physics/newtons_second_law_of_motion.py) @@ -792,6 +792,8 @@ * [Sol1](project_euler/problem_058/sol1.py) * Problem 059 * [Sol1](project_euler/problem_059/sol1.py) + * Problem 060 + * [Sol1](project_euler/problem_060/sol1.py) * Problem 062 * [Sol1](project_euler/problem_062/sol1.py) * Problem 063 diff --git a/project_euler/problem_060/__init__.py b/project_euler/problem_060/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/project_euler/problem_060/sol1.py b/project_euler/problem_060/sol1.py new file mode 100644 index 000000000000..2aaccdb9053a --- /dev/null +++ b/project_euler/problem_060/sol1.py @@ -0,0 +1,154 @@ +""" +Project Euler 60 +https://projecteuler.net/problem=60 + + + +The primes 3, 7, 109, and 673, are quite remarkable. +By taking any two primes and concatenating them in any order the +result will always be prime. +For example, taking 7 and 109, both 7109 and 1097 are prime. +The sum of these four primes, 792, represents the lowest sum for a +set of four primes with this property. + +Find the lowest sum for a set of five primes for which any two primes +concatenate to produce another prime. + +""" + +from math import sqrt + +pairs: list[str] = [] +minimum_sum = 0 +primes: list[str] = [] + + +def is_prime(number: int) -> bool: + """Checks to see if a number is a prime in O(sqrt(n)). + A number is prime if it has exactly two factors: 1 and itself. + + Taken from /maths/prime_check.py + + >>> is_prime(0) + False + >>> is_prime(1) + False + >>> is_prime(2) + True + >>> is_prime(3) + True + >>> is_prime(27) + False + >>> is_prime(87) + False + >>> is_prime(563) + True + >>> is_prime(2999) + True + >>> is_prime(67483) + False + """ + + # precondition + assert isinstance(number, int) and ( + number >= 0 + ), "'number' must been an int and positive" + + if 1 < number < 4: + # 2 and 3 are primes + return True + elif number < 2 or number % 2 == 0 or number % 3 == 0: + # Negatives, 0, 1, all even numbers, all multiples of 3 are not primes + return False + + # All primes number are in format of 6k +/- 1 + for i in range(5, int(sqrt(number) + 1), 6): + if number % i == 0 or number % (i + 2) == 0: + return False + return True + + +def combiner(index: int, length: int) -> bool: + """ + This function goes through all the combinations of the primes list in + ascending order, and finds pairs that satisfy the question until the + minimum_sum is low enough that it can stop and the minimum_sum is the minimum. + + Returns True if the recursion should continue else False. + + >>> combiner(1,2) + False + >>> combiner(2,3) + False + """ + + global pairs, minimum_sum + j = i = index # local variable j retains the original index and i gets changed + + if len(pairs) == length: # if it is one of the pairs we want + s = sum(int(x) for x in pairs) + if s < minimum_sum: + minimum_sum = s + primes.insert(i, pairs.pop(-1)) + return True + + while i < len(primes): + for prime in pairs: + if not is_prime(int(prime + primes[i])): + break + if not is_prime(int(primes[i] + prime)): + break + else: + pairs.append(primes.pop(i)) + if not combiner(i, length): + return False + + if pairs: + i += 1 + + if primes: + if j + len(pairs) - 1 != 0: + primes.insert(j, pairs.pop(-1)) + return True + else: + if int(pairs.pop(-1)) > minimum_sum / ( + 2 * 10 ** (length - 2) + ): # works for most test cases + return False + return True + return False + + +def solution(prime_count: int = 5, limit: int = 10000) -> int: + """ + The function returns the lowest sum for a set of n primes (prime_count) for which + any two primes concatenate to produce another prime. + + Limit is the maximum number of natural numbers to be checked up to. + + + >>> solution(2,10) + 10 + >>> solution(3,100) + 107 + >>> solution(4,1000) + 792 + """ + + global minimum_sum, primes, pairs + primes = [] + pairs = [] + for i in range(1, limit + 1): + if is_prime(i): + primes.append(str(i)) + minimum_sum = limit * 5 + combiner(0, prime_count) + return minimum_sum + + +if __name__ == "__main__": + import doctest + + doctest.testmod() + + print(f"{solution() = }") diff --git a/project_euler/problem_104/sol.py b/project_euler/problem_104/sol.py index 0818ac401c3a..10eb6d6e55f3 100644 --- a/project_euler/problem_104/sol.py +++ b/project_euler/problem_104/sol.py @@ -13,6 +13,10 @@ the last nine digits are 1-9 pandigital, find k. """ +import sys + +sys.set_int_max_str_digits(0) # type: ignore + def check(number: int) -> bool: """