From b5a188d8fd1d3aa1d948db5bad9d25c06986b916 Mon Sep 17 00:00:00 2001 From: Freddy Pringle Date: Mon, 7 Dec 2020 15:52:26 +0100 Subject: [PATCH 1/3] Added solution for Project Euler problem 180 --- project_euler/problem_180/__init__.py | 0 project_euler/problem_180/sol1.py | 153 ++++++++++++++++++++++++++ 2 files changed, 153 insertions(+) create mode 100644 project_euler/problem_180/__init__.py create mode 100644 project_euler/problem_180/sol1.py diff --git a/project_euler/problem_180/__init__.py b/project_euler/problem_180/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/project_euler/problem_180/sol1.py b/project_euler/problem_180/sol1.py new file mode 100644 index 000000000000..48b5f2210c88 --- /dev/null +++ b/project_euler/problem_180/sol1.py @@ -0,0 +1,153 @@ +""" +Project Euler Problem 234: https://projecteuler.net/problem=234 + +For any integer n, consider the three functions + +f1,n(x,y,z) = x^(n+1) + y^(n+1) - z^(n+1) +f2,n(x,y,z) = (xy + yz + zx)*(x^(n-1) + y^(n-1) - z^(n-1)) +f3,n(x,y,z) = xyz*(xn-2 + yn-2 - zn-2) + +and their combination + +fn(x,y,z) = f1,n(x,y,z) + f2,n(x,y,z) - f3,n(x,y,z) + +We call (x,y,z) a golden triple of order k if x, y, and z are all rational numbers +of the form a / b with 0 < a < b ≤ k and there is (at least) one integer n, +so that fn(x,y,z) = 0. + +Let s(x,y,z) = x + y + z. +Let t = u / v be the sum of all distinct s(x,y,z) for all golden triples +(x,y,z) of order 35. +All the s(x,y,z) and t must be in reduced form. + +Find u + v. + + +Solution: + +By expanding the brackets it is easy to show that +fn(x, y, z) = (x + y + z) * (x^n + y^n - z^n). + +Since x,y,z are positive, the requirement fn(x, y, z) = 0 is fulfilled if and +only if x^n + y^n = z^n. + +By Fermat's Last Theorem, this means that the absolute value of n can not +exceed 2, i.e. n is in {-2, -1, 0, 1, 2}. We can eliminate n = 0 since then the +equation would reduce to 1 + 1 = 1, for which there are no solutions. + +So all we have to do is iterate through the possible numerators and denominators +of x and y, calculate the corresponding z, and check if the corresponding numerator and +denominator are integer and satisfy 0 < z_num < z_den <= 0. We use a set "uniquq_s" +to make sure there are no duplicates, and the fractions.Fraction class to make sure +we get the right numerator and denominator. + +Reference: +https://en.wikipedia.org/wiki/Fermat%27s_Last_Theorem +""" + + +from fractions import Fraction +from math import gcd, sqrt + + +def is_sq(number: int) -> bool: + """ + Check if number is a perfect square. + + >>> is_sq(1) + True + >>> is_sq(1000001) + False + >>> is_sq(1000000) + True + """ + sq: int = int(number ** 0.5) + return number == sq * sq + + +def solution(order: int = 35) -> int: + """ + Find the sum of the numerator and denominator of the sum of all s(x,y,z) for + golden triples (x,y,z) of the given order. + + >>> solution(5) + 296 + >>> solution(10) + 12519 + >>> solution(20) + 19408891927 + """ + unique_s: set = set() + + def add(x_num: int, x_den: int, y_num: int, y_den: int, z_num: int, z_den: int): + top: int = x_num * y_den * z_den + y_num * x_den * z_den + z_num * x_den * y_den + bottom: int = x_den * y_den * z_den + _gcd: int = gcd(top, bottom) + top //= _gcd + bottom //= _gcd + unique_s.add((top, bottom)) + + x_num: int + x_den: int + y_num: int + y_den: int + z_num: int + z_den: int + lcm: int + + for x_num in range(1, order + 1): + for x_den in range(x_num + 1, order + 1): + for y_num in range(1, order + 1): + for y_den in range(y_num + 1, order + 1): + # n=1 + z_num = x_num * y_den + x_den * y_num + z_den = x_den * y_den + lcm = gcd(z_num, z_den) + z_num //= lcm + z_den //= lcm + if 0 < z_num < z_den <= order: + add(x_num, x_den, y_num, y_den, z_num, z_den) + + # n=2 + z_num = ( + x_num * x_num * y_den * y_den + x_den * x_den * y_num * y_num + ) + z_den = x_den * x_den * y_den * y_den + if is_sq(z_num) and is_sq(z_den): + z_num = int(sqrt(z_num)) + z_den = int(sqrt(z_den)) + lcm = gcd(z_num, z_den) + z_num //= lcm + z_den //= lcm + if 0 < z_num < z_den <= order: + add(x_num, x_den, y_num, y_den, z_num, z_den) + + # n=-1 + z_num = x_num * y_num + z_den = x_den * y_num + x_num * y_den + lcm = gcd(z_num, z_den) + z_num //= lcm + z_den //= lcm + if 0 < z_num < z_den <= order: + add(x_num, x_den, y_num, y_den, z_num, z_den) + + # n=2 + z_num = x_num * x_num * y_num * y_num + z_den = ( + x_den * x_den * y_num * y_num + x_num * x_num * y_den * y_den + ) + if is_sq(z_num) and is_sq(z_den): + z_num = int(sqrt(z_num)) + z_den = int(sqrt(z_den)) + lcm = gcd(z_num, z_den) + z_num //= lcm + z_den //= lcm + if 0 < z_num < z_den <= order: + add(x_num, x_den, y_num, y_den, z_num, z_den) + + total: Fraction = sum(map(lambda tup: Fraction(*tup), unique_s), Fraction()) + return total.denominator + total.numerator + + +if __name__ == "__main__": + print(solution()) From 803db4c629332258f6cce8509b04d2549b72274b Mon Sep 17 00:00:00 2001 From: Freddy Pringle Date: Wed, 9 Dec 2020 10:53:04 +0100 Subject: [PATCH 2/3] Fixed minor details in Project Euler problem 180 --- project_euler/problem_180/sol1.py | 89 +++++++++++++++++++------------ 1 file changed, 55 insertions(+), 34 deletions(-) diff --git a/project_euler/problem_180/sol1.py b/project_euler/problem_180/sol1.py index 48b5f2210c88..6112db2ea370 100644 --- a/project_euler/problem_180/sol1.py +++ b/project_euler/problem_180/sol1.py @@ -48,6 +48,7 @@ from fractions import Fraction from math import gcd, sqrt +from typing import Tuple def is_sq(number: int) -> bool: @@ -65,6 +66,25 @@ def is_sq(number: int) -> bool: return number == sq * sq +def add_three( + x_num: int, x_den: int, y_num: int, y_den: int, z_num: int, z_den: int +) -> Tuple[int, int]: + """ + Given the numerators and denominators of three fractions, return the + numerator and denominator of their sum in lowest form. + >>> add_three(1, 3, 1, 3, 1, 3) + (1, 1) + >>> add_three(2, 5, 4, 11, 12, 3) + (262, 55) + """ + top: int = x_num * y_den * z_den + y_num * x_den * z_den + z_num * x_den * y_den + bottom: int = x_den * y_den * z_den + hcf: int = gcd(top, bottom) + top //= hcf + bottom //= hcf + return top, bottom + + def solution(order: int = 35) -> int: """ Find the sum of the numerator and denominator of the sum of all s(x,y,z) for @@ -78,22 +98,9 @@ def solution(order: int = 35) -> int: 19408891927 """ unique_s: set = set() - - def add(x_num: int, x_den: int, y_num: int, y_den: int, z_num: int, z_den: int): - top: int = x_num * y_den * z_den + y_num * x_den * z_den + z_num * x_den * y_den - bottom: int = x_den * y_den * z_den - _gcd: int = gcd(top, bottom) - top //= _gcd - bottom //= _gcd - unique_s.add((top, bottom)) - - x_num: int - x_den: int - y_num: int - y_den: int - z_num: int - z_den: int - lcm: int + hcf: int + total: Fraction = Fraction(0) + fraction_sum: Tuple[int, int] for x_num in range(1, order + 1): for x_den in range(x_num + 1, order + 1): @@ -102,11 +109,14 @@ def add(x_num: int, x_den: int, y_num: int, y_den: int, z_num: int, z_den: int): # n=1 z_num = x_num * y_den + x_den * y_num z_den = x_den * y_den - lcm = gcd(z_num, z_den) - z_num //= lcm - z_den //= lcm + hcf = gcd(z_num, z_den) + z_num //= hcf + z_den //= hcf if 0 < z_num < z_den <= order: - add(x_num, x_den, y_num, y_den, z_num, z_den) + fraction_sum = add_three( + x_num, x_den, y_num, y_den, z_num, z_den + ) + unique_s.add(fraction_sum) # n=2 z_num = ( @@ -116,20 +126,26 @@ def add(x_num: int, x_den: int, y_num: int, y_den: int, z_num: int, z_den: int): if is_sq(z_num) and is_sq(z_den): z_num = int(sqrt(z_num)) z_den = int(sqrt(z_den)) - lcm = gcd(z_num, z_den) - z_num //= lcm - z_den //= lcm + hcf = gcd(z_num, z_den) + z_num //= hcf + z_den //= hcf if 0 < z_num < z_den <= order: - add(x_num, x_den, y_num, y_den, z_num, z_den) + fraction_sum = add_three( + x_num, x_den, y_num, y_den, z_num, z_den + ) + unique_s.add(fraction_sum) # n=-1 z_num = x_num * y_num z_den = x_den * y_num + x_num * y_den - lcm = gcd(z_num, z_den) - z_num //= lcm - z_den //= lcm + hcf = gcd(z_num, z_den) + z_num //= hcf + z_den //= hcf if 0 < z_num < z_den <= order: - add(x_num, x_den, y_num, y_den, z_num, z_den) + fraction_sum = add_three( + x_num, x_den, y_num, y_den, z_num, z_den + ) + unique_s.add(fraction_sum) # n=2 z_num = x_num * x_num * y_num * y_num @@ -139,15 +155,20 @@ def add(x_num: int, x_den: int, y_num: int, y_den: int, z_num: int, z_den: int): if is_sq(z_num) and is_sq(z_den): z_num = int(sqrt(z_num)) z_den = int(sqrt(z_den)) - lcm = gcd(z_num, z_den) - z_num //= lcm - z_den //= lcm + hcf = gcd(z_num, z_den) + z_num //= hcf + z_den //= hcf if 0 < z_num < z_den <= order: - add(x_num, x_den, y_num, y_den, z_num, z_den) + fraction_sum = add_three( + x_num, x_den, y_num, y_den, z_num, z_den + ) + unique_s.add(fraction_sum) + + for num, den in unique_s: + total += Fraction(num, den) - total: Fraction = sum(map(lambda tup: Fraction(*tup), unique_s), Fraction()) return total.denominator + total.numerator if __name__ == "__main__": - print(solution()) + print(f"{solution() = }") From 15d1e18cd41f1291d8f6e7bba0c89544d13a431a Mon Sep 17 00:00:00 2001 From: github-actions <${GITHUB_ACTOR}@users.noreply.github.com> Date: Wed, 9 Dec 2020 09:59:00 +0000 Subject: [PATCH 3/3] updating DIRECTORY.md --- DIRECTORY.md | 3 +++ 1 file changed, 3 insertions(+) diff --git a/DIRECTORY.md b/DIRECTORY.md index c9c3a09eb599..10523a85c48e 100644 --- a/DIRECTORY.md +++ b/DIRECTORY.md @@ -245,6 +245,7 @@ * [Max Sum Contiguous Subsequence](https://github.com/TheAlgorithms/Python/blob/master/dynamic_programming/max_sum_contiguous_subsequence.py) * [Minimum Cost Path](https://github.com/TheAlgorithms/Python/blob/master/dynamic_programming/minimum_cost_path.py) * [Minimum Partition](https://github.com/TheAlgorithms/Python/blob/master/dynamic_programming/minimum_partition.py) + * [Minimum Steps To One](https://github.com/TheAlgorithms/Python/blob/master/dynamic_programming/minimum_steps_to_one.py) * [Optimal Binary Search Tree](https://github.com/TheAlgorithms/Python/blob/master/dynamic_programming/optimal_binary_search_tree.py) * [Rod Cutting](https://github.com/TheAlgorithms/Python/blob/master/dynamic_programming/rod_cutting.py) * [Subset Generation](https://github.com/TheAlgorithms/Python/blob/master/dynamic_programming/subset_generation.py) @@ -754,6 +755,8 @@ * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_173/sol1.py) * Problem 174 * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_174/sol1.py) + * Problem 180 + * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_180/sol1.py) * Problem 188 * [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_188/sol1.py) * Problem 191