Use timing decorator for problems 61-70

This commit is contained in:
daniele 2023-06-07 20:27:05 +02:00
parent 5b99c1ef1c
commit f54083389b
Signed by: fuxino
GPG Key ID: 981A2B2A3BBF5514
10 changed files with 112 additions and 180 deletions

View File

@ -19,10 +19,10 @@
# Find the sum of the only ordered set of six cyclic 4-digit numbers for which each polygonal type: triangle, square, pentagonal,
# hexagonal, heptagonal, and octagonal, is represented by a different number in the set.
from timeit import default_timer
from numpy import zeros
from projecteuler import timing
polygonal = zeros((6, 10000), int)
chain = [0] * 6
@ -30,47 +30,40 @@ flags = [0] * 6
sum_ = 0
# Recursive function to find the required set. It finds a polygonal number,
# check if it can be part of the chain, then use recursion to find the next
# number. If a solution can't be found with the current numbers, it uses
# backtracking and tries the next polygonal number.
# Recursive function to find the required set. It finds a polygonal number, check if it can be part of the chain, then use recursion to find the next
# number. If a solution can't be found with the current numbers, it uses backtracking and tries the next polygonal number.
def find_set(step):
global sum_
# Use one polygonal number per type, starting from triangular.
# Use one polygonal number per type, starting from triangular.
for i in range(6):
# If the current type has not been used yet, try it.
# If the current type has not been used yet, try it.
if flags[i] == 0:
# Set a flag to record that the current polygonal type has been used.
# Set a flag to record that the current polygonal type has been used.
flags[i] = 1
# Start from 1010 because numbers finishing with 00, 01, ..., 09 can't
# be part of the chain.
# Start from 1010 because numbers finishing with 00, 01, ..., 09 can't be part of the chain.
for j in range(1010, 10000):
# If the number doesn't finish with 00, 01, ..., 09 and is poligonal,
# try adding it to the chain and add its value to the total sum.
# If the number doesn't finish with 00, 01, ..., 09 and is poligonal,
# try adding it to the chain and add its value to the total sum.
if j % 100 > 9 and polygonal[i, j] == 1:
# If it's the first number, just add it as first step in the chain.
# If it's the first number, just add it as first step in the chain.
if step == 0:
chain[step] = j
sum_ += j
# Recursively try to add other numbers to the chain. If a solution
# is found, return 1.
# Recursively try to add other numbers to the chain. If a solution is found, return 1.
if find_set(step+1):
return 1
# If a solution was not found, backtrack, subtracting the value of
# the number from the total.
# If a solution was not found, backtrack, subtracting the value of the number from the total.
sum_ -= j
# If this is the last step and the current number can be added to the chain,
# add it, update the sum and return 1. A solution has been found.
# If this is the last step and the current number can be added to the chain, add it, update the sum and return 1. A solution has been found.
elif step == 5 and j % 100 == chain[0] // 100 and j // 100 == chain[step-1] % 100:
chain[step] = j
sum_ += j
return 1
# For every other step, add the number to the chain if possible, then recursively
# try to add other numbers.
# For every other step, add the number to the chain if possible, then recursively try to add other numbers.
elif step < 5 and j // 100 == chain[step-1] % 100:
chain[step] = j
sum_ += + j
@ -78,22 +71,21 @@ def find_set(step):
if find_set(step+1):
return 1
# If a solution was not found, backtrack.
# If a solution was not found, backtrack.
sum_ -= j
# Remove the flag for the current polygonal type.
# Remove the flag for the current polygonal type.
flags[i] = 0
return 0
def main():
start = default_timer()
@timing
def p061():
i = 1
n = 1
# Generate all triangle numbers smaller than 10000
# Generate all triangle numbers smaller than 10000
while True:
polygonal[0, n] = 1
i = i + 1
@ -105,7 +97,7 @@ def main():
i = 1
n = 1
# Generate all square numbers smaller than 10000
# Generate all square numbers smaller than 10000
while True:
polygonal[1, n] = 1
i = i + 1
@ -117,7 +109,7 @@ def main():
i = 1
n = 1
# Generate all pentagonal numbers smaller than 10000
# Generate all pentagonal numbers smaller than 10000
while True:
polygonal[2, n] = 1
i = i + 1
@ -129,7 +121,7 @@ def main():
i = 1
n = 1
# Generate all hexagonal numbers smaller than 10000
# Generate all hexagonal numbers smaller than 10000
while True:
polygonal[3, n] = 1
i = i + 1
@ -141,7 +133,7 @@ def main():
i = 1
n = 1
# Generate all heptagonal numbers smaller than 10000
# Generate all heptagonal numbers smaller than 10000
while True:
polygonal[4, n] = 1
i = i + 1
@ -152,7 +144,8 @@ def main():
i = 1
n = 1
# Generate all octagonal numbers smaller than 10000
# Generate all octagonal numbers smaller than 10000
while True:
polygonal[5, n] = 1
i = i + 1
@ -161,17 +154,13 @@ def main():
if n >= 10000:
break
# Find the requested set of numbers
# Find the requested set of numbers
if find_set(0) == 0:
print('Set not found')
end = default_timer()
print('Project Euler, Problem 61')
print(f'Answer: {sum_}')
print(f'Elapsed time: {end - start:.9f} seconds')
if __name__ == '__main__':
main()
p061()

View File

@ -5,30 +5,29 @@
#
# Find the smallest cube for which exactly five permutations of its digits are cube.
from timeit import default_timer
from numpy import zeros
from projecteuler import timing
def main():
start = default_timer()
@timing
def p062():
N = 10000
cubes = zeros(N, int)
# Calculate i^3 for all i smaller than 10000
# Calculate i^3 for all i smaller than 10000
for i in range(N):
cubes[i] = i * i * i
# For each cube, check if there are four other cubes which are also
# a permutation of the first cube.
# For each cube, check if there are four other cubes which are also
# a permutation of the first cube.
for i in range(N-5):
count = 1
# Stop when the limit has been reached, when 5 values have been found or
# when j^3 has more digits than i^3 (if they don't have the same digits,
# they can't be permutations).
# Stop when the limit has been reached, when 5 values have been found or
# when j^3 has more digits than i^3 (if they don't have the same digits,
# they can't be permutations).
j = i + 1
while j < N and len(str(cubes[j])) == len(str(cubes[i])):
@ -43,13 +42,9 @@ def main():
if count == 5:
break
end = default_timer()
print('Project Euler, Problem 62')
print(f'Answer: {cubes[i]}')
print(f'Elapsed time: {end - start:.9f} seconds')
if __name__ == '__main__':
main()
p062()

View File

@ -4,37 +4,32 @@
#
# How many n-digit positive integers exist which are also an nth power?
from timeit import default_timer
from projecteuler import timing
def main():
start = default_timer()
@timing
def p063():
i = 1
count = 0
finished = 0
while not finished:
# When j=10, j^i will have i+1 digits (e.g. if i=3, 10^3=1000).
# When j=10, j^i will have i+1 digits (e.g. if i=3, 10^3=1000).
for j in range(1, 10):
p = j ** i
if len(str(p)) == i:
count = count + 1
# When 9^i has less than i digits, all the numbers have been found.
# When 9^i has less than i digits, all the numbers have been found.
if len(str(p)) < i:
finished = 1
i = i + 1
end = default_timer()
print('Project Euler, Problem 63')
print(f'Answer: {count}')
print(f'Elapsed time: {end - start:.9f} seconds')
if __name__ == '__main__':
main()
p063()

View File

@ -43,9 +43,8 @@
# How many continued fractions for N≤10000 have an odd period?
from math import sqrt
from timeit import default_timer
from projecteuler import build_sqrt_cont_fraction
from projecteuler import build_sqrt_cont_fraction, timing
def is_square(n):
@ -55,28 +54,23 @@ def is_square(n):
return bool(p == m)
def main():
start = default_timer()
@timing
def p064():
count = 0
for i in range(2, 10000):
# Perfect squares are obviously not represented as continued fractions.
# For all other numbers, calculate their period and check if it's odd.
# Perfect squares are obviously not represented as continued fractions.
# For all other numbers, calculate their period and check if it's odd.
if not is_square(i):
# period_cf(i) % 2 != 0:
fraction, period = build_sqrt_cont_fraction(i, 300)
# period_cf(i) % 2 != 0:
_, period = build_sqrt_cont_fraction(i, 300)
if period % 2 != 0:
count = count + 1
end = default_timer()
print('Project Euler, Problem 64')
print(f'Answer: {count}')
print(f'Elapsed time: {end - start:.9f} seconds')
if __name__ == '__main__':
main()
p064()

View File

@ -29,12 +29,11 @@
#
# Find the sum of digits in the numerator of the 100th convergent of the continued fraction for e.
from timeit import default_timer
from projecteuler import timing
def main():
start = default_timer()
@timing
def p065():
ai = [1, 2, 1]
count = 4
@ -42,14 +41,14 @@ def main():
n1 = 8
n2 = 11
# For a continued fractions [a_0; a_1, a_2, ...], the numerator of the
# next convergent N_n=a_n*N_(n-1)+N_(n-2). The first three values for e are
# 3, 8 and 11, the next ones are easily calculated, considering that a_n
# follows a simple pattern:
# a_1=1, a_2=2, a_3=1
# a_4=1, a_5=4, a_6=1
# a_7=1, a_8=6, a_9=1
# and so on.
# For a continued fractions [a_0; a_1, a_2, ...], the numerator of the
# next convergent N_n=a_n*N_(n-1)+N_(n-2). The first three values for e are
# 3, 8 and 11, the next ones are easily calculated, considering that a_n
# follows a simple pattern:
# a_1=1, a_2=2, a_3=1
# a_4=1, a_5=4, a_6=1
# a_7=1, a_8=6, a_9=1
# and so on.
while count < 100:
ai[1] = ai[1] + 2
@ -68,13 +67,9 @@ def main():
sum_ = sum_ + n2 % 10
n2 = n2 // 10
end = default_timer()
print('Project Euler, Problem 65')
print(f'Answer: {sum_}')
print(f'Elapsed time: {end - start:.9f} seconds')
if __name__ == '__main__':
main()
p065()

View File

@ -21,9 +21,8 @@
# Find the value of D ≤ 1000 in minimal solutions of x for which the largest value of x is obtained.
from math import sqrt
from timeit import default_timer
from projecteuler import pell_eq
from projecteuler import pell_eq, timing
def is_square(n):
@ -33,28 +32,23 @@ def is_square(n):
return bool(p == m)
def main():
start = default_timer()
@timing
def p066():
max_ = 0
max_d = -1
for i in range(2, 1001):
if not is_square(i):
# Solve the Diophantine equation x^2-D*y^2=1 (Pell equation)
# Solve the Diophantine equation x^2-D*y^2=1 (Pell equation)
x = pell_eq(i)
if x > max_:
max_ = x
max_d = i
end = default_timer()
print('Project Euler, Problem 66')
print(f'Answer: {max_d}')
print(f'Elapsed time: {end - start:.9f} seconds')
if __name__ == '__main__':
main()
p066()

View File

@ -16,14 +16,12 @@
# There is an efficient algorithm to solve it. ;o)
import sys
from timeit import default_timer
from projecteuler import find_max_path
from projecteuler import find_max_path, timing
def main():
start = default_timer()
@timing
def p067():
triang = []
try:
@ -39,16 +37,12 @@ def main():
for i in range(l):
triang[i] = list(map(int, triang[i]))
# Use the function implemented in projecteuler.c to find the maximum path.
# Use the function implemented in projecteuler.c to find the maximum path.
max_ = find_max_path(triang, 100)
end = default_timer()
print('Project Euler, Problem 67')
print(f'Answer: {max_}')
print(f'Elapsed time: {end - start:.9f} seconds')
if __name__ == '__main__':
main()
p067()

View File

@ -46,7 +46,8 @@
#
from itertools import permutations
from timeit import default_timer
from projecteuler import timing
# Function to evaluate the ring. The ring is represented as a vector of 2*n elements,
@ -54,38 +55,36 @@ from timeit import default_timer
# represent the internal ring.
def eval_ring(ring, n):
for i in range(1, n):
# We need to start from the lowest external node, so if
# the first element in the vector is not the lowest of
# the first n elements (the external elements), the configuration
# is not a valid one.
# We need to start from the lowest external node, so if
# the first element in the vector is not the lowest of
# the first n elements (the external elements), the configuration
# is not a valid one.
if ring[i] < ring[0]:
return None
res = [0] * 3 * n
# Each group of three must have the same value.
# Each group of three must have the same value.
magic_val = ring[0] + ring[n] + ring[n+1]
j = 0
for i in range(n):
# We need to find the maximum 16-digit string, this is
# possible only if the element "10" is used only once,
# i.e. if it's one of the external nodes.
if ring[n+i] == 10 or ring[n+(i+1)%n] == 10:
# We need to find the maximum 16-digit string, this is possible only if the element "10" is used only once,
# i.e. if it's one of the external nodes.
if ring[n+i] == 10 or ring[n+(i+1) % n] == 10:
return None
# Check that the value of the current three-element group
# is the "magic" value.
val = ring[i] + ring[n+i] + ring[n+(i+1)%n]
# Check that the value of the current three-element group is the "magic" value.
val = ring[i] + ring[n+i] + ring[n+(i+1) % n]
if val != magic_val :
if val != magic_val:
return None
# Save the current element group in the result string.
# Save the current element group in the result string.
res[j] = ring[i]
res[j+1] = ring[n+i]
res[j+2] = ring[n+(i+1)%n]
res[j+2] = ring[n+(i+1) % n]
j = j + 3
@ -110,11 +109,9 @@ def list_to_int(l):
return res
def main():
start = default_timer()
# Generate all possible permutations, for each one check if
# it's a possible solution for the ring and save the maximum
@timing
def p068():
# Generate all possible permutations, for each one check if it's a possible solution for the ring and save the maximum
rings = list(permutations(list(range(1, 11))))
max_ = 0
n = None
@ -122,19 +119,15 @@ def main():
for ring in rings:
eval_ = eval_ring(ring, 5)
# Convert the list into an integer number.
# Convert the list into an integer number.
n = list_to_int(eval_)
if n > max_:
max_ = n
end = default_timer()
print('Project Euler, Problem 68')
print(f'Answer: {max_}')
print(f'Elapsed time: {end - start:.9f} seconds')
if __name__ == '__main__':
main()
p068()

View File

@ -18,41 +18,34 @@
#
# Find the value of n ≤ 1,000,000 for which n/φ(n) is a maximum.
from timeit import default_timer
from projecteuler import is_prime
from projecteuler import is_prime, timing
def main():
start = default_timer()
@timing
def p069():
N = 1000000
i = 1
res = 1
# Using Euler's formula, phi(n)=n*prod(1-1/p), where p are the distinct
# primes that divide n. So n/phi(n)=1/prod(1-1/p). To find the maximum
# value of this function, the denominator must be minimized. This happens
# when n has the most distinct small prime factor, i.e. to find the solution
# we need to multiply the smallest consecutive primes until the result is
# larger than 1000000.
# Using Euler's formula, phi(n)=n*prod(1-1/p), where p are the distinct
# primes that divide n. So n/phi(n)=1/prod(1-1/p). To find the maximum
# value of this function, the denominator must be minimized. This happens
# when n has the most distinct small prime factor, i.e. to find the solution
# we need to multiply the smallest consecutive primes until the result is
# larger than 1000000.
while res < N:
i = i + 1
if is_prime(i):
res = res * i
# We need the previous value, because we want i<1000000
# We need the previous value, because we want i<1000000
res = res // i
end = default_timer()
print('Project Euler, Problem 69')
print(f'Answer: {res}')
print(f'Elapsed time: {end - start:.9f} seconds')
if __name__ == '__main__':
main()
p069()

View File

@ -9,14 +9,11 @@
#
# Find the value of n, 1 < n < 10^7, for which φ(n) is a permutation of n and the ratio n/φ(n) produces a minimum.
from timeit import default_timer
from projecteuler import sieve, is_semiprime, phi_semiprime
from projecteuler import sieve, is_semiprime, phi_semiprime, timing
def main():
start = default_timer()
@timing
def p070():
N = 10000000
n = -1
min_ = float('inf')
@ -25,12 +22,9 @@ def main():
primes = sieve(N)
for i in range(2, N):
# When n is prime, phi(n)=(n-1), so to minimize n/phi(n) we should
# use n prime. But n-1 can't be a permutation of n. The second best
# bet is to use semiprimes. For a semiprime n=p*q, phi(n)=(p-1)(q-1).
# So we check if a number is semiprime, if yes calculate phi, finally
# check if phi(n) is a permutation of n and update the minimum if it's
# smaller.
# When n is prime, phi(n)=(n-1), so to minimize n/phi(n) we should use n prime. But n-1 can't be a permutation of n. The second best
# bet is to use semiprimes. For a semiprime n=p*q, phi(n)=(p-1)(q-1). So we check if a number is semiprime, if yes calculate phi, finally
# check if phi(n) is a permutation of n and update the minimum if it's smaller.
semi_p, a, b = is_semiprime(i, primes)
if semi_p is True:
@ -40,13 +34,9 @@ def main():
n = i
min_ = i / p
end = default_timer()
print('Project Euler, Problem 70')
print(f'Answer: {n}')
print(f'Elapsed time: {end - start:.9f} seconds')
if __name__ == '__main__':
main()
p070()