[英]Project Euler #23 - Python Non Abundant Sums
我一直致力于Project Euler #23
。
这是任务:
问题 23
完美数是一个数,其真因数之和正好等于该数。 例如,28 的适当因数之和为 1 + 2 + 4 + 7 + 14 = 28,这意味着 28 是一个完美数。
一个数 n 如果其真因数之和小于 n 则称为不足数,如果该数之和超过 n 则称为丰富数。
由于 12 是最小的丰度数,1 + 2 + 3 + 4 + 6 = 16,所以可以写成两个丰度数之和的最小数是 24。通过数学分析可以证明,所有大于28123 可以写成两个丰富数之和。 然而,这个上限不能通过分析进一步降低>即使已知不能表示为两个丰富数之和的最大数小于这个限制。
找出所有不能写成两个丰富数之和的正整数之和。
这是我的代码:
import math
def getDivisors(num):
n = math.ceil(math.sqrt(num))
total = 1
divisor = 2
while (divisor < n):
if (num%divisor == 0):
total += divisor
total += num//divisor
divisor+=1
return total
def isAbundant(num):
if (getDivisors(num) > num):
return True
else:
return False
abundentNums = []
for x in range (0,28124):
if (isAbundant(x)):
abundentNums.append(x)
del abundentNums[0]
sums = [0]*28124
for x in range (0, len(abundentNums)):
for y in range (x, len(abundentNums)):
sumOf2AbundantNums = abundentNums[x]+abundentNums[y]
if (sumOf2AbundantNums<= 28123):
if (sums[sumOf2AbundantNums] == 0):
sums[sumOf2AbundantNums] = sumOf2AbundantNums
total = 0
for x in range (1,len(sums)):
if (sums[x] == 0):
total +=x
print('\n', total)
我得到的总值是4190404
。 正确答案是4179871
我花了一个小时查看我的代码,但我找不到错误。 我应该改变什么来纠正错误? 我的答案很接近。 提前致谢
PS。 我是 python 的新手。 运行时间为 25 秒,任何优化也将很有用。
您的getDivisors
函数不正确。 它不计算平方数的除数(例如,如果num=25
,它将返回 1)。 这是一个更正的版本:
def getDivisors(num):
if num==1:
return 1
n = math.ceil(math.sqrt(num))
total = 1
divisor = 2
while (divisor < n):
if (num%divisor == 0):
total += divisor
total += num//divisor
divisor+=1
if n**2==num:
total+=n
return total
使用这个函数,我得到了所需的结果4179871
。
我对上面提到的代码做了一些更改,我在 13 秒内得到了正确的答案。 我的 CPU 是英特尔酷睿 i5。 这是我的代码:
from array import array
import math
def find_abundant(number):
sum_factor = 1
value = math.ceil(math.sqrt(number))
if number == 1:
return False
for i in range(2, value):
if number % i == 0:
sum_factor += (i+(number//i))
if value**2 == number:
sum_factor += value
if sum_factor > number:
return True
else:
return False
numbers = [0]*28123
abundant_numbers = array("i", [])
for abundant in range(1, 28124):
if find_abundant(abundant):
abundant_numbers.append(abundant)
for x in abundant_numbers:
for y in abundant_numbers[0:abundant_numbers.index(x)+1]:
z = x+y
if z < 28124 and numbers[z-1] == 0:
numbers[z-1] = z
_sum = 0
for vary in range(1, len(numbers)+1):
if numbers[vary-1] == 0:
_sum += vary
print(_sum)}
此代码在我的计算机上运行 6 秒:
from math import sqrt
import itertools
import functools
import operator
#simplicity test
def fuc(a):
d = 1
z = 0
while d<= sqrt(a):
d = d + 1
if a == 2:
z = a
elif (a%d) == 0:
z = False
break
else:
z = a
return z
#prime number divisors
def func(value):
v = []
d = 1
value1= value# for optimization
while d <= sqrt(value1):
d+=1
if fuc(d)!= False and value1 % d == 0:
v.append(d)
value1 = value1/d
d = 1
if value1 != value and value1 != 1:
v.append(value1)
return v
# all number divisors without 1 and source number
def calculate_devisors(n):
prime_multiples_list = func(n)
unique_combinations = set()
for i in range(1, len(prime_multiples_list)):
unique_combinations.update(set(itertools.combinations(prime_multiples_list,i)))
combinations_product = list(functools.reduce(operator.mul,i) for i in unique_combinations)
combinations_product.sort()
try:
return combinations_product
except:
return []
abundentNums = []
for n in range(1,28123):
if sum(calculate_devisors(n))+1>n:
abundentNums.append(n)
sums = [0]*28124
for x in range (0, len(abundentNums)):
for y in range (x, len(abundentNums)):
sumOf2AbundantNums = abundentNums[x]+abundentNums[y]
if (sumOf2AbundantNums<= 28123):
if (sums[sumOf2AbundantNums] == 0):
sums[sumOf2AbundantNums] = sumOf2AbundantNums
ans = 0
for i in range(1,len(sums)):
if sums[i]==0:
ans+=i
print(ans)
我发现这些小的调整可能有助于减少总时间。 我在大约 4 秒钟内在我的电脑上得到了。
from math import sqrt
from itertools import compress
start = time.process_time()
abundant_nos = []
for i in range(12,28123):
factor = 0
for j in range(2,int(sqrt(i))+1):
if i%j == 0:
factor+= j + i//j
if j == sqrt(i):
factor -= j
if factor>i:
abundant_nos.append(i)
num_list = [True]*28123
k = 0
for i in abundant_nos:
for j in abundant_nos[k:]:
if(i+j>28123): break
num_list[i+j-1] = False
k+=1
answer = sum(compress(range(1,28124),num_list))
print(answer)
numpy 的一种可能解决方案可以避免嵌套循环,并且在我的笔记本电脑上通常时间少于 3 秒,如下(使用您的丰富数字列表“abundentNums”时):
## transform to numpy array
A = np.array(abundentNums)
## make array of all numbers from 1 to limit in problem
B = np.linspace(1,28123,28123)
## use an outer sum to create matrix that contains all possible sum-combinations of abundant numbers below the limit. And delete duplicate entries
C = np.unique(np.add.outer(A, A)[(np.add.outer(A, A) < 28124)])
## difference between the sum of all numbers to limit and sum of all numbers that CAN be expressed as sum of two abundant numbers is the quantity looked for
ans = int(np.sum(B) - np.sum(C))
因此,包括 Miriam Farber 更正的 getDivisors function 在内的整个代码是
import math
import numpy as np
def getDivisors(num):
if num==1:
return 1
n = math.ceil(math.sqrt(num))
total = 1
divisor = 2
while (divisor < n):
if (num%divisor == 0):
total += divisor
total += num//divisor
divisor+=1
if n**2==num:
total+=n
return total
def isAbundant(num):
if (getDivisors(num) > num):
return True
else:
return False
abundentNums = []
for x in range (0,28124):
if (isAbundant(x)):
abundentNums.append(x)
del abundentNums[0]
## transform to numpy array
A = np.array(abundentNums)
## make array of all numbers from 1 to limit in problem
B = np.linspace(1,28123,28123)
## use an outer sum to create matrix that contains all possible sum-combinations of abundant numbers below the limit. And delete duplicate entries
C = np.unique(np.add.outer(A, A)[(np.add.outer(A, A) < 28124)])
## difference between the sum of all numbers to limit and sum of all numbers that CAN be expressed as sum of two abundant numbers is the quantity looked for
ans = int(np.sum(B) - np.sum(C))
列出丰富数字列表的列表理解进一步减少了必要的时间。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.