我正在研究Project Euler Problem 50,其中指出:
素数41,可以写成六个连续素数的总和:
41 = 2 + 3 + 5 + 7 + 11 + 13 这是连续素数的最长和,它增加到低于一百的素数。
连续素数低于一千的最长和,加上素数,包含21个项,等于953。
哪个素数低于一百万,可以写成最连续素数的总和?
为了确定素数 P 中的项(如果它可以写成素数之和)我使用所有素数的滑动窗口(按递增顺序)到(但不是包括) P ,并计算所有这些窗口的总和,如果总和等于考虑的素数,我计算窗口的长度......
这对于 1000 的所有素数都适用,但对于 10 ** 6 的素数,它非常慢,所以我希望 memozation < / strong>会有所帮助;在计算滑动窗口的总和时,进行了大量的双重工作......(对吗?)
所以我在网上找到了标准的memoizaton实现,并将其粘贴在我的代码中,这是正确的吗? (我不知道它应该如何在这里工作......)
primes = tuple(n for n in range(1, 10**6) if is_prime(n)==True)
count_best = 0
##http://docs.python.org/release/2.3.5/lib/itertools-example.html:
## Slightly modified (first for loop)
from itertools import islice
def window(seq):
for n in range(2, len(seq) + 1):
it = iter(seq)
result = tuple(islice(it, n))
if len(result) == n:
yield result
for elem in it:
result = result[1:] + (elem,)
yield result
def memoize(function):
cache = {}
def decorated_function(*args):
if args in cache:
return cache[args]
else:
val = function(*args)
cache[args] = val
return val
return decorated_function
@memoize
def find_lin_comb(prime):
global count_best
for windows in window(primes[0 : primes.index(prime)]):
if sum(windows) == prime and len(windows) > count_best:
count_best = len(windows)
print('Prime: ', prime, 'Terms: ', count_best)
##Find them:
for x in primes[::-1]: find_lin_comb(x)
(顺便说一句,素数的元组是“正常”快速生成的)
所有的输入都很受欢迎,我只是一个爱好程序员,所以请不要对我有所帮助。
谢谢!
编辑:这是一个没有破坏缩进的工作代码粘贴: http://pastebin.com/R1NpMqgb
答案 0 :(得分:3)
这适用于1000以下的所有素数,但对于高达10 ** 6的素数来说它非常慢,所以我希望备忘录会有所帮助;在计算滑动窗口的总和时,进行了大量的双重工作......(对吗?)
是的,没错。当然,素数达到10 6 的速度很慢。
假设您n
素数最多为N
,按递增顺序编号p_1 = 2, p_2 = 3, ...
。在考虑是否素数没有。对于k
对[p_i, ..., p_j]
,(i,j)
是连续素数的总和,您考虑所有窗口i < j < k
。其中有(k-1)*(k-2)/2
个。通过所有k
到n
,您可以检查总共n³/6
个窗口(计算多重性,您总共w(i.j)
次检查n-j
次。即使忽略了创建窗口并对其进行求和的成本,您也可以看到它的扩展程度如何:
N = 1000
,有n = 168
素数和约790000个窗口需要检查(计算多重性)。N = 10**6
,有n = 78498
个素数和约8.3*10**13
个窗口需要检查。现在考虑创建和汇总窗口的工作,估算j-i+1
的低j-i+1
总和w(i,j)
中的p_k
素数,k³/6
的工作是关于k**4/24
,总工作量大致为N = 1000
。对1.6*10**18
花生而言,有3300万步,而N = 1000000
几乎为3.1*10**7
。
一年包含大约n³/6
秒,具有~3GHz的CPU,大约10 17 时钟周期。所以我们谈论的是需要100个CPU年的操作(可能是10个左右的因素)。
我想,你不愿意等那么久;)
现在,通过记忆,您仍然会多次查看每个窗口,但是您只对每个窗口进行一次计算。这意味着你需要n³/6
工作来计算窗口,并在任何窗口查看8.3*10**13
次。
8.3*10**13
次的窗口,即使只花费一个周期也需要几个小时。您可以通过丢弃不再需要的数据来规避内存问题,并且只在需要时计算窗口的数据,但是一旦您知道可能丢弃的数据,您应该能够看到更好的方法。
连续素数低于一千的最长和,加上素数,包含21个项,等于953。
这告诉你关于产生这笔金额的窗口是什么?哪里可以开始,哪里可以停止?如何使用该信息创建一个有效的算法来解决问题?
答案 1 :(得分:1)
memoize装饰器为函数添加一个包装器,以缓存参数的每个值的返回值(多个参数的每个值组合)。当使用相同的参数多次调用函数时,它很有用。您只能使用纯函数,即
您的find_lin_comb函数不符合上述条件。首先,每次都使用不同的参数调用它,另一方面,函数不返回值。