项目Euler#23 Python

时间:2017-02-28 02:17:58

标签: python algorithm

所以我正在研究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)

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

2 个答案:

答案 0 :(得分:0)

你可以只有一个28124布尔值的列表,初始化为False。然后迭代大量数字,并为每个数字找到数字等于或大于它的所有总和。对于每个和x,在列表True中设置第x个标志。由于丰富的数字是按升序排列的,当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!

答案 1 :(得分: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秒