Solve problem 70 in Python.
This commit is contained in:
@@ -66,7 +66,7 @@ def euler_068():
|
|||||||
if is_5_gon_ring(p):
|
if is_5_gon_ring(p):
|
||||||
r = five_gon_ring_to_group_presentation(p)
|
r = five_gon_ring_to_group_presentation(p)
|
||||||
if len(r) == 16:
|
if len(r) == 16:
|
||||||
print(r)
|
# print(r)
|
||||||
rs.append(int(r))
|
rs.append(int(r))
|
||||||
return max(rs)
|
return max(rs)
|
||||||
|
|
||||||
|
|||||||
@@ -1,13 +1,4 @@
|
|||||||
from lib_prime import primes
|
from lib_prime import primes
|
||||||
from lib_misc import gcd
|
|
||||||
|
|
||||||
|
|
||||||
def relative_primes_count(n):
|
|
||||||
return len([i for i in range(1, n) if gcd(n, i) == 1])
|
|
||||||
|
|
||||||
|
|
||||||
def get_phi(n):
|
|
||||||
return n / relative_primes_count(n)
|
|
||||||
|
|
||||||
|
|
||||||
def euler_069():
|
def euler_069():
|
||||||
|
|||||||
106
python/e070.py
Normal file
106
python/e070.py
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
from lib_misc import gcd
|
||||||
|
from lib_misc import is_permutation
|
||||||
|
|
||||||
|
|
||||||
|
class Primes(object):
|
||||||
|
def __init__(self, n_max):
|
||||||
|
import bitarray
|
||||||
|
self.n_max = n_max
|
||||||
|
b = bitarray.bitarray(n_max)
|
||||||
|
b.setall(True)
|
||||||
|
n = 1
|
||||||
|
b[n - 1] = False
|
||||||
|
while n * n <= n_max:
|
||||||
|
if b[n - 1] is True:
|
||||||
|
for i in range(n + n, n_max + 1, n):
|
||||||
|
b[i - 1] = False
|
||||||
|
n += 1
|
||||||
|
self.b = b
|
||||||
|
|
||||||
|
def iter_down(self):
|
||||||
|
for i in range(self.n_max, 0, -1):
|
||||||
|
if self.b[i - 1]:
|
||||||
|
yield i
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
def iter_up(self):
|
||||||
|
for i in range(1, self.n_max + 1):
|
||||||
|
if self.b[i - 1]:
|
||||||
|
yield i
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
def iter_range(self, n_min, n_max):
|
||||||
|
for i in range(n_min, n_max + 1):
|
||||||
|
if self.b[i - 1]:
|
||||||
|
yield i
|
||||||
|
raise StopIteration
|
||||||
|
|
||||||
|
def is_prime(self, n):
|
||||||
|
if n > self.n_max:
|
||||||
|
raise Exception("n greater than n_max")
|
||||||
|
return self.b[n - 1]
|
||||||
|
|
||||||
|
|
||||||
|
def relative_primes_count_naiv(n):
|
||||||
|
return len([i for i in range(1, n) if gcd(n, i) == 1])
|
||||||
|
|
||||||
|
|
||||||
|
def relative_primes_count_factors(n, fs):
|
||||||
|
from itertools import combinations
|
||||||
|
rel_primes_count = n - 1 # n itself is not a relative prime
|
||||||
|
for f in fs:
|
||||||
|
rel_primes_count -= (n // f - 1)
|
||||||
|
for f_1, f_2 in combinations(fs, 2):
|
||||||
|
f = f_1 * f_2
|
||||||
|
rel_primes_count += (n // f - 1)
|
||||||
|
return rel_primes_count
|
||||||
|
|
||||||
|
|
||||||
|
def get_phi(n):
|
||||||
|
r = relative_primes_count_naiv(n)
|
||||||
|
return n / r
|
||||||
|
|
||||||
|
|
||||||
|
def get_phi_factors(n, fs):
|
||||||
|
r = relative_primes_count_factors(n, fs)
|
||||||
|
return n / r
|
||||||
|
|
||||||
|
|
||||||
|
def euler_070():
|
||||||
|
"""
|
||||||
|
I struggled harder than I should have with this problem. I realized
|
||||||
|
quickly that a prime can't be the solution because a prime minus one
|
||||||
|
cannot be a permutation of itself. I then figured that the solution is
|
||||||
|
probably a number with two prime factors. I implemented an algorithm, but
|
||||||
|
it did not yield the right solution.
|
||||||
|
|
||||||
|
I tried a couple of things like squaring one prime factor which does not
|
||||||
|
yield a solution at all and three factors. Finally, I came up with a
|
||||||
|
faster algorithm to get the number of relative primes faster. With that
|
||||||
|
procedure I was then able to bruteforce the problem in 10 minutes.
|
||||||
|
|
||||||
|
When analyzing the solution I saw that it actually consists of two primes
|
||||||
|
which means my orginal algorithm had a bug. After reimplenting it was able
|
||||||
|
to find the solution in under 30 seconds. We could further optimize this
|
||||||
|
by making the search range for the two factors smaller. """
|
||||||
|
n = 10**7
|
||||||
|
ps = Primes(n // 1000)
|
||||||
|
phi_min = 1000
|
||||||
|
n_phi_min = 0
|
||||||
|
|
||||||
|
for p_1 in ps.iter_down():
|
||||||
|
for p_2 in ps.iter_range(1000, n // 1000):
|
||||||
|
n_new = p_1 * p_2
|
||||||
|
if n_new > n:
|
||||||
|
break
|
||||||
|
rel_primes_n_new = relative_primes_count_factors(n_new, [p_1, p_2])
|
||||||
|
phi_new = n_new / rel_primes_n_new
|
||||||
|
if phi_new < phi_min and is_permutation(n_new, rel_primes_n_new):
|
||||||
|
phi_min = phi_new
|
||||||
|
n_phi_min = n_new
|
||||||
|
return n_phi_min
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("e070.py: " + str(euler_070()))
|
||||||
|
assert(euler_070() == 8319823)
|
||||||
8
python/e071.py
Normal file
8
python/e071.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
def euler_071():
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("e071.py: " + str(euler_071()))
|
||||||
|
assert(euler_071() == 0)
|
||||||
8
python/e072.py
Normal file
8
python/e072.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
def euler_072():
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("e072.py: " + str(euler_072()))
|
||||||
|
assert(euler_072() == 0)
|
||||||
8
python/e073.py
Normal file
8
python/e073.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
def euler_073():
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("e073.py: " + str(euler_073()))
|
||||||
|
assert(euler_073() == 0)
|
||||||
8
python/e074.py
Normal file
8
python/e074.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
def euler_074():
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("e074.py: " + str(euler_074()))
|
||||||
|
assert(euler_074() == 0)
|
||||||
8
python/e075.py
Normal file
8
python/e075.py
Normal file
@@ -0,0 +1,8 @@
|
|||||||
|
|
||||||
|
def euler_075():
|
||||||
|
return 0
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == "__main__":
|
||||||
|
print("e075.py: " + str(euler_075()))
|
||||||
|
assert(euler_075() == 0)
|
||||||
@@ -1,5 +1,5 @@
|
|||||||
FROM = 68
|
FROM = 70
|
||||||
TILL = 68
|
TILL = 75
|
||||||
|
|
||||||
template = """
|
template = """
|
||||||
def euler_XXX():
|
def euler_XXX():
|
||||||
|
|||||||
@@ -206,3 +206,14 @@ def get_digit_count(n):
|
|||||||
Returns the number of digits for n.
|
Returns the number of digits for n.
|
||||||
"""
|
"""
|
||||||
return len(str(n))
|
return len(str(n))
|
||||||
|
|
||||||
|
|
||||||
|
def is_permutation(n, p):
|
||||||
|
""" Checks if p is a permutation of n. """
|
||||||
|
digit_counts_n = [0 for _ in range(10)]
|
||||||
|
digit_counts_p = [0 for _ in range(10)]
|
||||||
|
for d_n in str(n):
|
||||||
|
digit_counts_n[int(d_n)] += 1
|
||||||
|
for p_n in str(p):
|
||||||
|
digit_counts_p[int(p_n)] += 1
|
||||||
|
return digit_counts_n == digit_counts_p
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ try:
|
|||||||
from .lib_misc import permutations
|
from .lib_misc import permutations
|
||||||
from .lib_misc import gcd
|
from .lib_misc import gcd
|
||||||
from .lib_misc import get_digit_count
|
from .lib_misc import get_digit_count
|
||||||
|
from .lib_misc import is_permutation
|
||||||
except ModuleNotFoundError:
|
except ModuleNotFoundError:
|
||||||
from lib_misc import is_palindrome_integer
|
from lib_misc import is_palindrome_integer
|
||||||
from lib_misc import is_palindrome_string
|
from lib_misc import is_palindrome_string
|
||||||
@@ -29,6 +30,7 @@ except ModuleNotFoundError:
|
|||||||
from lib_misc import permutations
|
from lib_misc import permutations
|
||||||
from lib_misc import gcd
|
from lib_misc import gcd
|
||||||
from lib_misc import get_digit_count
|
from lib_misc import get_digit_count
|
||||||
|
from lib_misc import is_permutation
|
||||||
|
|
||||||
|
|
||||||
class TestPrimeMethods(unittest.TestCase):
|
class TestPrimeMethods(unittest.TestCase):
|
||||||
@@ -137,6 +139,12 @@ class TestPrimeMethods(unittest.TestCase):
|
|||||||
self.assertEqual(get_digit_count(1), 1)
|
self.assertEqual(get_digit_count(1), 1)
|
||||||
self.assertEqual(get_digit_count(1234567890), 10)
|
self.assertEqual(get_digit_count(1234567890), 10)
|
||||||
|
|
||||||
|
def test_is_permutation(self):
|
||||||
|
self.assertTrue(is_permutation(123, 321))
|
||||||
|
self.assertTrue(is_permutation(123, 321))
|
||||||
|
self.assertFalse(is_permutation(12, 321))
|
||||||
|
self.assertFalse(is_permutation(1235, 4321))
|
||||||
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
if __name__ == '__main__':
|
||||||
unittest.main()
|
unittest.main()
|
||||||
|
|||||||
Reference in New Issue
Block a user