Skip to content

Problem 180 #4017

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Dec 9, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions DIRECTORY.md
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down Expand Up @@ -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
Expand Down
Empty file.
174 changes: 174 additions & 0 deletions project_euler/problem_180/sol1.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,174 @@
"""
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
from typing import Tuple


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 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
golden triples (x,y,z) of the given order.

>>> solution(5)
296
>>> solution(10)
12519
>>> solution(20)
19408891927
"""
unique_s: set = set()
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):
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
hcf = gcd(z_num, z_den)
z_num //= hcf
z_den //= hcf
if 0 < z_num < z_den <= order:
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_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))
hcf = gcd(z_num, z_den)
z_num //= hcf
z_den //= hcf
if 0 < z_num < z_den <= order:
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
hcf = gcd(z_num, z_den)
z_num //= hcf
z_den //= hcf
if 0 < z_num < z_den <= order:
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
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))
hcf = gcd(z_num, z_den)
z_num //= hcf
z_den //= hcf
if 0 < z_num < z_den <= order:
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)

return total.denominator + total.numerator


if __name__ == "__main__":
print(f"{solution() = }")