Skip to content

Commit 8f072e9

Browse files
fpringlegithub-actions
authored andcommitted
Add Project Euler Problem 180 (TheAlgorithms#4017)
* Added solution for Project Euler problem 180 * Fixed minor details in Project Euler problem 180 * updating DIRECTORY.md Co-authored-by: github-actions <${GITHUB_ACTOR}@users.noreply.github.com>
1 parent 6dd3ccb commit 8f072e9

File tree

3 files changed

+177
-0
lines changed

3 files changed

+177
-0
lines changed

Diff for: DIRECTORY.md

+3
Original file line numberDiff line numberDiff line change
@@ -245,6 +245,7 @@
245245
* [Max Sum Contiguous Subsequence](https://github.com/TheAlgorithms/Python/blob/master/dynamic_programming/max_sum_contiguous_subsequence.py)
246246
* [Minimum Cost Path](https://github.com/TheAlgorithms/Python/blob/master/dynamic_programming/minimum_cost_path.py)
247247
* [Minimum Partition](https://github.com/TheAlgorithms/Python/blob/master/dynamic_programming/minimum_partition.py)
248+
* [Minimum Steps To One](https://github.com/TheAlgorithms/Python/blob/master/dynamic_programming/minimum_steps_to_one.py)
248249
* [Optimal Binary Search Tree](https://github.com/TheAlgorithms/Python/blob/master/dynamic_programming/optimal_binary_search_tree.py)
249250
* [Rod Cutting](https://github.com/TheAlgorithms/Python/blob/master/dynamic_programming/rod_cutting.py)
250251
* [Subset Generation](https://github.com/TheAlgorithms/Python/blob/master/dynamic_programming/subset_generation.py)
@@ -754,6 +755,8 @@
754755
* [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_173/sol1.py)
755756
* Problem 174
756757
* [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_174/sol1.py)
758+
* Problem 180
759+
* [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_180/sol1.py)
757760
* Problem 188
758761
* [Sol1](https://github.com/TheAlgorithms/Python/blob/master/project_euler/problem_188/sol1.py)
759762
* Problem 191

Diff for: project_euler/problem_180/__init__.py

Whitespace-only changes.

Diff for: project_euler/problem_180/sol1.py

+174
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,174 @@
1+
"""
2+
Project Euler Problem 234: https://projecteuler.net/problem=234
3+
4+
For any integer n, consider the three functions
5+
6+
f1,n(x,y,z) = x^(n+1) + y^(n+1) - z^(n+1)
7+
f2,n(x,y,z) = (xy + yz + zx)*(x^(n-1) + y^(n-1) - z^(n-1))
8+
f3,n(x,y,z) = xyz*(xn-2 + yn-2 - zn-2)
9+
10+
and their combination
11+
12+
fn(x,y,z) = f1,n(x,y,z) + f2,n(x,y,z) - f3,n(x,y,z)
13+
14+
We call (x,y,z) a golden triple of order k if x, y, and z are all rational numbers
15+
of the form a / b with 0 < a < b ≤ k and there is (at least) one integer n,
16+
so that fn(x,y,z) = 0.
17+
18+
Let s(x,y,z) = x + y + z.
19+
Let t = u / v be the sum of all distinct s(x,y,z) for all golden triples
20+
(x,y,z) of order 35.
21+
All the s(x,y,z) and t must be in reduced form.
22+
23+
Find u + v.
24+
25+
26+
Solution:
27+
28+
By expanding the brackets it is easy to show that
29+
fn(x, y, z) = (x + y + z) * (x^n + y^n - z^n).
30+
31+
Since x,y,z are positive, the requirement fn(x, y, z) = 0 is fulfilled if and
32+
only if x^n + y^n = z^n.
33+
34+
By Fermat's Last Theorem, this means that the absolute value of n can not
35+
exceed 2, i.e. n is in {-2, -1, 0, 1, 2}. We can eliminate n = 0 since then the
36+
equation would reduce to 1 + 1 = 1, for which there are no solutions.
37+
38+
So all we have to do is iterate through the possible numerators and denominators
39+
of x and y, calculate the corresponding z, and check if the corresponding numerator and
40+
denominator are integer and satisfy 0 < z_num < z_den <= 0. We use a set "uniquq_s"
41+
to make sure there are no duplicates, and the fractions.Fraction class to make sure
42+
we get the right numerator and denominator.
43+
44+
Reference:
45+
https://en.wikipedia.org/wiki/Fermat%27s_Last_Theorem
46+
"""
47+
48+
49+
from fractions import Fraction
50+
from math import gcd, sqrt
51+
from typing import Tuple
52+
53+
54+
def is_sq(number: int) -> bool:
55+
"""
56+
Check if number is a perfect square.
57+
58+
>>> is_sq(1)
59+
True
60+
>>> is_sq(1000001)
61+
False
62+
>>> is_sq(1000000)
63+
True
64+
"""
65+
sq: int = int(number ** 0.5)
66+
return number == sq * sq
67+
68+
69+
def add_three(
70+
x_num: int, x_den: int, y_num: int, y_den: int, z_num: int, z_den: int
71+
) -> Tuple[int, int]:
72+
"""
73+
Given the numerators and denominators of three fractions, return the
74+
numerator and denominator of their sum in lowest form.
75+
>>> add_three(1, 3, 1, 3, 1, 3)
76+
(1, 1)
77+
>>> add_three(2, 5, 4, 11, 12, 3)
78+
(262, 55)
79+
"""
80+
top: int = x_num * y_den * z_den + y_num * x_den * z_den + z_num * x_den * y_den
81+
bottom: int = x_den * y_den * z_den
82+
hcf: int = gcd(top, bottom)
83+
top //= hcf
84+
bottom //= hcf
85+
return top, bottom
86+
87+
88+
def solution(order: int = 35) -> int:
89+
"""
90+
Find the sum of the numerator and denominator of the sum of all s(x,y,z) for
91+
golden triples (x,y,z) of the given order.
92+
93+
>>> solution(5)
94+
296
95+
>>> solution(10)
96+
12519
97+
>>> solution(20)
98+
19408891927
99+
"""
100+
unique_s: set = set()
101+
hcf: int
102+
total: Fraction = Fraction(0)
103+
fraction_sum: Tuple[int, int]
104+
105+
for x_num in range(1, order + 1):
106+
for x_den in range(x_num + 1, order + 1):
107+
for y_num in range(1, order + 1):
108+
for y_den in range(y_num + 1, order + 1):
109+
# n=1
110+
z_num = x_num * y_den + x_den * y_num
111+
z_den = x_den * y_den
112+
hcf = gcd(z_num, z_den)
113+
z_num //= hcf
114+
z_den //= hcf
115+
if 0 < z_num < z_den <= order:
116+
fraction_sum = add_three(
117+
x_num, x_den, y_num, y_den, z_num, z_den
118+
)
119+
unique_s.add(fraction_sum)
120+
121+
# n=2
122+
z_num = (
123+
x_num * x_num * y_den * y_den + x_den * x_den * y_num * y_num
124+
)
125+
z_den = x_den * x_den * y_den * y_den
126+
if is_sq(z_num) and is_sq(z_den):
127+
z_num = int(sqrt(z_num))
128+
z_den = int(sqrt(z_den))
129+
hcf = gcd(z_num, z_den)
130+
z_num //= hcf
131+
z_den //= hcf
132+
if 0 < z_num < z_den <= order:
133+
fraction_sum = add_three(
134+
x_num, x_den, y_num, y_den, z_num, z_den
135+
)
136+
unique_s.add(fraction_sum)
137+
138+
# n=-1
139+
z_num = x_num * y_num
140+
z_den = x_den * y_num + x_num * y_den
141+
hcf = gcd(z_num, z_den)
142+
z_num //= hcf
143+
z_den //= hcf
144+
if 0 < z_num < z_den <= order:
145+
fraction_sum = add_three(
146+
x_num, x_den, y_num, y_den, z_num, z_den
147+
)
148+
unique_s.add(fraction_sum)
149+
150+
# n=2
151+
z_num = x_num * x_num * y_num * y_num
152+
z_den = (
153+
x_den * x_den * y_num * y_num + x_num * x_num * y_den * y_den
154+
)
155+
if is_sq(z_num) and is_sq(z_den):
156+
z_num = int(sqrt(z_num))
157+
z_den = int(sqrt(z_den))
158+
hcf = gcd(z_num, z_den)
159+
z_num //= hcf
160+
z_den //= hcf
161+
if 0 < z_num < z_den <= order:
162+
fraction_sum = add_three(
163+
x_num, x_den, y_num, y_den, z_num, z_den
164+
)
165+
unique_s.add(fraction_sum)
166+
167+
for num, den in unique_s:
168+
total += Fraction(num, den)
169+
170+
return total.denominator + total.numerator
171+
172+
173+
if __name__ == "__main__":
174+
print(f"{solution() = }")

0 commit comments

Comments
 (0)