项目Euler#23 Python

问题描述 投票:0回答:2

所以我正在研究Project Euler#23,我需要一些效率帮助。

好的,原来的问题是:

完美数字是一个数字,其正确除数的总和恰好等于数字。例如,28的适当除数之和为1 + 2 + 4 + 7 + 14 = 28,这意味着28是一个完美数。

如果n的适当除数之和小于n,则数n被称为不足,如果该和超过n,则称其为n。

由于12是最小的有限数,1 + 2 + 3 + 4 + 6 = 16,可以写成两个有限数之和的最小数是24.通过数学分析,可以证明所有整数都大于28123可以写成两个数字的总和。然而,即使已知不能表示为两个充裕数的总和的最大数量小于该限制,也不能通过分析进一步减小该上限。

找到所有正整数的总和,这些正整数不能写为两个数字的总和。

我已经让大部分代码高效运行,但我遇到的一个问题就是找到所有数字都是两个数字的总和。

import math
import time
def factors(n):
    fact=[1,n]
    check=2
    rootn=math.sqrt(n)
    while check<rootn:
        if n%check==0:
                fact.append(check)
                fact.append(n/check)
        check+=1
    if rootn==check:
        fact.append(check)
    fact.sort()
    return fact

abundantNumbers = []
timeStart = time.time()
for i in range(12, 28124):
    factorTemp = factors(i)
    totalTemp = 0
    factorTemp.remove(i)
    for j in range(len(factorTemp)):
        factorTemp[j] = float(factorTemp[j])
    for j in range(len(factorTemp)):
        totalTemp+=factorTemp[j]
        if totalTemp> i:
            abundantNumbers.append(i)
            break
nums = []
doubleAbu = []
for i in range(24, 28124):
    nums.append(i)

for j in abundantNumbers:
    if j*2 < 28123 and j*2 not in doubleAbu:
        doubleAbu.append(j*2)

for i in abundantNumbers:
    repeat=True
    for j in abundantNumbers[abundantNumbers.index(i):]:
        if i + j not in doubleAbu and i + j <28123:
            doubleAbu.append(i+j)
        elif i + j > 28123:
            break
            repeat = False
    if not repeat:
        break
total = 0
for i in range(len(doubleAbu)):
    nums.remove(doubleAbu[i])
for i in range(len(nums)):
    total += nums[i]


print("It took, ", str(time.time()-timeStart), " seconds!")
#print((abundantNumbers))
print(doubleAbu)
print(total)

我已经做了相当多的研究,我确信有数以千计的方法做得比我好,但是如果有人有任何方程或只是更好的方法来找到正整数,这是两个数量的总和我可以使用一些帮助。

python algorithm
2个回答
0
投票

您可以只有一个28124布尔值的列表,初始化为False。然后迭代大量数字,并为每个数字找到数字等于或大于它的所有总和。对于每个和x,在列表True中设置xth标志。由于数量是按升序排列的,当sum大于28123时,你可以打破内循环。然后在最后一步迭代列表并将所有具有False值的indeces加在一起:

import math
import time
def factors(n):
    fact=[1,n]
    check=2
    rootn=math.sqrt(n)
    while check<rootn:
        if n%check==0:
                fact.append(check)
                fact.append(n//check)
        check+=1
    if rootn==check:
        fact.append(check)
    fact.sort()
    return fact

abundantNumbers = []
timeStart = time.time()
for i in range(12, 28124):
    factorTemp = factors(i)
    totalTemp = 0
    factorTemp.remove(i)
    for j in range(len(factorTemp)):
        factorTemp[j] = float(factorTemp[j])
    for j in range(len(factorTemp)):
        totalTemp+=factorTemp[j]
        if totalTemp> i:
            abundantNumbers.append(i)
            break

MAX = 28123
result = [False] * (MAX + 1)

for i in range(len(abundantNumbers)):
    for j in range(i, len(abundantNumbers)):
        s = abundantNumbers[i] + abundantNumbers[j]
        if s > MAX:
            break
        result[s] = True

print(sum(i for i, x in enumerate(result) if not x))
print("It took, ", str(time.time()-timeStart), " seconds!")

输出:

4179871
It took,  3.190303325653076  seconds!

0
投票

有一个更快更短的版本,虽然我很确定它仍然可以改进。

import time
from math import ceil

# Sum of Proper Divisors of
def sopd(n):
    if n == 1: return 0
    s = 1
    sqrt = ceil(n ** 0.5)
    for b in range(2, sqrt):
        if n % b == 0:
            s += (b + n // b)
    return s + (sqrt if sqrt ** 2 == n else 0)

if __name__ == '__main__':
    start_time = time.time()

    abundant = set()
    s = 0
    for i in range(1,28124):
        if not any(i-a in abundant for a in abundant):
            s += i
        if sopd(i) > i:
            abundant.add(i)
    print(s)
    print("--- {} seconds ---".format(time.time() - start_time))

我的电脑需要大约1.2秒

© www.soinside.com 2019 - 2024. All rights reserved.