Improve problem 75 in Python.
parent
a451cd0db6
commit
45692feacb
|
@ -1,4 +1,5 @@
|
||||||
from math import sqrt
|
from math import sqrt
|
||||||
|
from lib_misc import gcd
|
||||||
|
|
||||||
|
|
||||||
def proper_divisors(n):
|
def proper_divisors(n):
|
||||||
|
@ -28,16 +29,6 @@ def triples_brute_force(b_max):
|
||||||
return triples
|
return triples
|
||||||
|
|
||||||
|
|
||||||
def triples_euclids_formula(m, n):
|
|
||||||
""" Does not return all triples! """
|
|
||||||
assert(m > n)
|
|
||||||
assert(n > 0)
|
|
||||||
a = m * m - n * n
|
|
||||||
b = 2 * m * n
|
|
||||||
c = m * m + n * n
|
|
||||||
return (a, b, c)
|
|
||||||
|
|
||||||
|
|
||||||
def dicksons_method(r):
|
def dicksons_method(r):
|
||||||
triples = []
|
triples = []
|
||||||
assert(r % 2 == 0)
|
assert(r % 2 == 0)
|
||||||
|
@ -94,7 +85,7 @@ def dicksons_method_efficient(r):
|
||||||
return perimeters
|
return perimeters
|
||||||
|
|
||||||
|
|
||||||
def euler_075():
|
def euler_075_dicksons():
|
||||||
"""
|
"""
|
||||||
We are using Dickson's method to get all Pythagorean triples. The
|
We are using Dickson's method to get all Pythagorean triples. The
|
||||||
challenge is that this method requires finding the divisors for a
|
challenge is that this method requires finding the divisors for a
|
||||||
|
@ -130,6 +121,57 @@ def euler_075():
|
||||||
return one_integer_sided_right_triangle_count
|
return one_integer_sided_right_triangle_count
|
||||||
|
|
||||||
|
|
||||||
|
def triples_euclids_formula(m, n):
|
||||||
|
"""
|
||||||
|
Generates only primitive triples.
|
||||||
|
https://en.wikipedia.org/wiki/Pythagorean_triple#Generating_a_triple
|
||||||
|
"""
|
||||||
|
assert(m > n)
|
||||||
|
assert(n > 0)
|
||||||
|
assert(gcd(m, n) == 1)
|
||||||
|
assert(m % 2 == 0 or n % 2 == 0)
|
||||||
|
a = m * m - n * n
|
||||||
|
b = 2 * m * n
|
||||||
|
c = m * m + n * n
|
||||||
|
if a < b:
|
||||||
|
return (a, b, c)
|
||||||
|
else:
|
||||||
|
return (b, a, c)
|
||||||
|
|
||||||
|
|
||||||
|
def euler_075():
|
||||||
|
"""
|
||||||
|
The range for m was chosen empirically (aka by trial and error).
|
||||||
|
I tried terminating when L > L_max the first time, but there might
|
||||||
|
be combinations for m = m + 1 that yield lower L. I guess the right
|
||||||
|
criteria to return would be if L > L_max and n == 1.
|
||||||
|
This is good enough for now. I still like my other solution, but it
|
||||||
|
is so much slower because finding the divisors is so expensive.
|
||||||
|
"""
|
||||||
|
L = 0
|
||||||
|
L_max = 1500000
|
||||||
|
m = 1
|
||||||
|
perimeter_counts = {}
|
||||||
|
for m in range(1, 1000):
|
||||||
|
for n in range(1, m):
|
||||||
|
try:
|
||||||
|
L = sum(triples_euclids_formula(m, n))
|
||||||
|
L_k = L
|
||||||
|
while L_k <= L_max:
|
||||||
|
try:
|
||||||
|
perimeter_counts[L_k] += 1
|
||||||
|
except KeyError:
|
||||||
|
perimeter_counts[L_k] = 1
|
||||||
|
L_k += L
|
||||||
|
except AssertionError:
|
||||||
|
pass
|
||||||
|
one_integer_sided_right_triangle_count = 0
|
||||||
|
for perimeter, count in perimeter_counts.items():
|
||||||
|
if count == 1:
|
||||||
|
one_integer_sided_right_triangle_count += 1
|
||||||
|
return one_integer_sided_right_triangle_count
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print("e075.py: " + str(euler_075()))
|
print("e075.py: " + str(euler_075()))
|
||||||
assert(euler_075() == 161667)
|
assert(euler_075() == 161667)
|
||||||
|
|
Loading…
Reference in New Issue