Improve problem 75 in Python.
parent
a451cd0db6
commit
45692feacb
|
@ -1,4 +1,5 @@
|
|||
from math import sqrt
|
||||
from lib_misc import gcd
|
||||
|
||||
|
||||
def proper_divisors(n):
|
||||
|
@ -28,16 +29,6 @@ def triples_brute_force(b_max):
|
|||
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):
|
||||
triples = []
|
||||
assert(r % 2 == 0)
|
||||
|
@ -94,7 +85,7 @@ def dicksons_method_efficient(r):
|
|||
return perimeters
|
||||
|
||||
|
||||
def euler_075():
|
||||
def euler_075_dicksons():
|
||||
"""
|
||||
We are using Dickson's method to get all Pythagorean triples. The
|
||||
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
|
||||
|
||||
|
||||
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__":
|
||||
print("e075.py: " + str(euler_075()))
|
||||
assert(euler_075() == 161667)
|
||||
|
|
Loading…
Reference in New Issue