繁体   English   中英

欧拉计划 #23 - Python 非充足金额

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM