Solve problem 78 and 79 in Python.
This commit is contained in:
122
python/e078.py
122
python/e078.py
@@ -1,8 +1,126 @@
|
|||||||
|
from functools import lru_cache
|
||||||
|
|
||||||
|
|
||||||
def euler_078():
|
def euler_078():
|
||||||
return 0
|
piles_look_up = {}
|
||||||
|
|
||||||
|
def count_piles_limited(n, max_size):
|
||||||
|
if max_size == 1:
|
||||||
|
return 1
|
||||||
|
try:
|
||||||
|
return piles_look_up[(n, max_size)]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
for i in range(1, n):
|
||||||
|
n_new = n - i
|
||||||
|
count_i = count_piles_limited(n_new, min([n_new, i]))
|
||||||
|
count += count_i
|
||||||
|
piles_look_up[(n, i)] = count
|
||||||
|
# for n itself
|
||||||
|
count += 1
|
||||||
|
piles_look_up[(n, n)] = count
|
||||||
|
return count
|
||||||
|
|
||||||
|
piles_look_up_modular = {}
|
||||||
|
|
||||||
|
def count_piles_limited_modular(n, max_size, modulu):
|
||||||
|
if max_size == 1:
|
||||||
|
return 1
|
||||||
|
try:
|
||||||
|
return piles_look_up_modular[(n, max_size)]
|
||||||
|
except KeyError:
|
||||||
|
pass
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
for i in range(1, n):
|
||||||
|
n_new = n - i
|
||||||
|
count_i = count_piles_limited_modular(
|
||||||
|
n_new, min([n_new, i]), modulu)
|
||||||
|
count = (count + count_i) % modulu
|
||||||
|
piles_look_up_modular[(n, i)] = count
|
||||||
|
# for n itself
|
||||||
|
count = (count + 1) % modulu
|
||||||
|
piles_look_up_modular[(n, n)] = count
|
||||||
|
return count
|
||||||
|
|
||||||
|
@lru_cache(maxsize=1000000)
|
||||||
|
def count_piles(n, max_size):
|
||||||
|
if max_size == 0 or max_size == 1:
|
||||||
|
return 1
|
||||||
|
if n == 0 or n == 1:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
count = 0
|
||||||
|
for k in range(1, max_size + 1):
|
||||||
|
n_new = n - k
|
||||||
|
max_size_new = min([k, n_new])
|
||||||
|
count += count_piles(n_new, max_size_new)
|
||||||
|
return count
|
||||||
|
|
||||||
|
"""
|
||||||
|
I tried to implement my own algorithm but I would run out of memory.
|
||||||
|
I tried to find a pattern in how the count can be calculated directly,
|
||||||
|
but I could not find a pattern. I then looked up partioning and
|
||||||
|
implemented the algorithm explained here [1]. This was literally the first
|
||||||
|
time in my life that I have learned about generator functions. Once I
|
||||||
|
used this algorithm it was easy. I definitely want to learn more about
|
||||||
|
generator functions.
|
||||||
|
|
||||||
|
[1] https://www.coursera.org/lecture/enumerative-combinatorics/computing-the-number-of-partitions-via-the-pentagonal-theorem-CehOM
|
||||||
|
"""
|
||||||
|
|
||||||
|
def sign(n):
|
||||||
|
if n % 2 == 0:
|
||||||
|
return -1
|
||||||
|
return 1
|
||||||
|
|
||||||
|
@lru_cache(maxsize=1000000)
|
||||||
|
def euler_identity(n):
|
||||||
|
r = (3 * n * n - n) // 2
|
||||||
|
return r
|
||||||
|
|
||||||
|
@lru_cache(maxsize=1000000)
|
||||||
|
def p(n):
|
||||||
|
"""
|
||||||
|
"""
|
||||||
|
if n == 0:
|
||||||
|
return 1
|
||||||
|
if n == 1:
|
||||||
|
return 1
|
||||||
|
|
||||||
|
m = 1000000
|
||||||
|
r = 0
|
||||||
|
for i in range(1, n):
|
||||||
|
s = sign(i)
|
||||||
|
|
||||||
|
e = euler_identity(i)
|
||||||
|
new_n = n - e
|
||||||
|
if new_n < 0:
|
||||||
|
break
|
||||||
|
if m:
|
||||||
|
r = (r + s * p(new_n)) % m
|
||||||
|
else:
|
||||||
|
r = r + s * p(new_n)
|
||||||
|
|
||||||
|
e = euler_identity(-i)
|
||||||
|
new_n = n - e
|
||||||
|
if new_n < 0:
|
||||||
|
break
|
||||||
|
if m:
|
||||||
|
r = (r + s * p(new_n)) % m
|
||||||
|
else:
|
||||||
|
r = r + s * p(new_n)
|
||||||
|
return r
|
||||||
|
|
||||||
|
for n in range(1, 100000):
|
||||||
|
a = p(n)
|
||||||
|
if a == 0:
|
||||||
|
return n
|
||||||
|
break
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print("e078.py: " + str(euler_078()))
|
print("e078.py: " + str(euler_078()))
|
||||||
assert(euler_078() == 0)
|
assert(euler_078() == 55374)
|
||||||
|
|||||||
@@ -1,8 +1,94 @@
|
|||||||
|
|
||||||
|
def verify(passcode, rule):
|
||||||
|
"""
|
||||||
|
Passcode is a string of numbers. Rule is two character string "ab". Verify
|
||||||
|
returns False if "a" occurs and never comes before "b" at some point in
|
||||||
|
the passcode and True otherwise.
|
||||||
|
"""
|
||||||
|
a, b = rule
|
||||||
|
if a == b:
|
||||||
|
return True
|
||||||
|
a_found = False
|
||||||
|
b_found = False
|
||||||
|
result = True
|
||||||
|
for c in passcode:
|
||||||
|
if a == c:
|
||||||
|
a_found = True
|
||||||
|
if b == c:
|
||||||
|
b_found = True
|
||||||
|
if b_found and c == a:
|
||||||
|
result = False
|
||||||
|
if a_found and c == b:
|
||||||
|
return True
|
||||||
|
return result
|
||||||
|
|
||||||
|
|
||||||
|
def verify_all(passcode, rules):
|
||||||
|
for rule in rules:
|
||||||
|
if not verify(passcode, rule):
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
|
||||||
|
def tests():
|
||||||
|
passcode = "abcded"
|
||||||
|
assert(verify(passcode, "ab"))
|
||||||
|
assert(verify(passcode, "cz"))
|
||||||
|
assert(verify(passcode, "zc"))
|
||||||
|
assert(verify(passcode, "bb"))
|
||||||
|
assert(verify(passcode, "ed"))
|
||||||
|
assert(verify(passcode, "fg"))
|
||||||
|
assert(verify(passcode, "ac"))
|
||||||
|
assert(verify(passcode, "de"))
|
||||||
|
assert(verify(passcode, "ca") is False)
|
||||||
|
assert(verify(passcode, "dc") is False)
|
||||||
|
|
||||||
|
|
||||||
|
def get_rules(passcodes):
|
||||||
|
rules = []
|
||||||
|
for p in passcodes:
|
||||||
|
for i in range(len(p) - 1):
|
||||||
|
rules.append(p[i:i + 2])
|
||||||
|
return rules
|
||||||
|
|
||||||
|
|
||||||
|
def get_digits(passcodes):
|
||||||
|
r = []
|
||||||
|
for p in passcodes:
|
||||||
|
for d in p:
|
||||||
|
if d not in r:
|
||||||
|
r.append(d)
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
|
def add_single_digit(code, digit):
|
||||||
|
# print("add_single_digit({}, {})".format(code, digit))
|
||||||
|
r = []
|
||||||
|
for i in range(len(code) + 1):
|
||||||
|
new_code = code[:i] + str(digit) + code[i:]
|
||||||
|
r.append(new_code)
|
||||||
|
return r
|
||||||
|
|
||||||
|
|
||||||
def euler_079():
|
def euler_079():
|
||||||
return 0
|
tests()
|
||||||
|
with open("../txt/EulerProblem079.txt", "r") as f:
|
||||||
|
passcodes = sorted(list(set([line.strip() for line in f])))
|
||||||
|
|
||||||
|
codes = [""]
|
||||||
|
rules = get_rules(passcodes)
|
||||||
|
|
||||||
|
for d in get_digits(passcodes):
|
||||||
|
temp_codes = []
|
||||||
|
for code in codes:
|
||||||
|
if d not in code:
|
||||||
|
for new_code in add_single_digit(code, d):
|
||||||
|
if verify_all(new_code, rules):
|
||||||
|
temp_codes.append(new_code)
|
||||||
|
codes = temp_codes
|
||||||
|
return int(codes[0])
|
||||||
|
|
||||||
|
|
||||||
if __name__ == "__main__":
|
if __name__ == "__main__":
|
||||||
print("e079.py: " + str(euler_079()))
|
print("e079.py: " + str(euler_079()))
|
||||||
assert(euler_079() == 0)
|
assert(euler_079() == 73162890)
|
||||||
|
|||||||
50
txt/EulerProblem079.txt
Normal file
50
txt/EulerProblem079.txt
Normal file
@@ -0,0 +1,50 @@
|
|||||||
|
319
|
||||||
|
680
|
||||||
|
180
|
||||||
|
690
|
||||||
|
129
|
||||||
|
620
|
||||||
|
762
|
||||||
|
689
|
||||||
|
762
|
||||||
|
318
|
||||||
|
368
|
||||||
|
710
|
||||||
|
720
|
||||||
|
710
|
||||||
|
629
|
||||||
|
168
|
||||||
|
160
|
||||||
|
689
|
||||||
|
716
|
||||||
|
731
|
||||||
|
736
|
||||||
|
729
|
||||||
|
316
|
||||||
|
729
|
||||||
|
729
|
||||||
|
710
|
||||||
|
769
|
||||||
|
290
|
||||||
|
719
|
||||||
|
680
|
||||||
|
318
|
||||||
|
389
|
||||||
|
162
|
||||||
|
289
|
||||||
|
162
|
||||||
|
718
|
||||||
|
729
|
||||||
|
319
|
||||||
|
790
|
||||||
|
680
|
||||||
|
890
|
||||||
|
362
|
||||||
|
319
|
||||||
|
760
|
||||||
|
316
|
||||||
|
729
|
||||||
|
380
|
||||||
|
319
|
||||||
|
728
|
||||||
|
716
|
||||||
Reference in New Issue
Block a user