如何找到n作为尘埃素数的和(当n是偶数时)

时间:2018-08-18 15:24:00

标签: functional-programming

此问题为您提供一个小于或等于100000(10 ^ 5)的正整数。您必须找出该号码的以下内容:

i。是素数吗?如果它是质数,则打印是。

ii。如果数字不是质数,那么我们可以将数字表示为唯一质数的总和吗?如果可能,则打印是。在这里,独特的意思是,您只能一次使用任何质数。

如果以上两个条件对于任何整数均失败,则打印NO。有关更多说明,请参见输入,输出部分及其说明。

输入 首先,给您一个整数T(T <= 100),它是测试用例的数量。对于每种情况,您都将得到一个小于或等于100000的正整数X。

输出 对于每个测试用例,仅打印YES或NO。

样本 输入输出 3 7 6 10是 没有 是 情况– 1说明:7是质数。

情况– 2说明:6不是质数。 6可以表示为6 = 3 + 3或6 = 2 + 2 +2。但是,任何质数都不能使用超过1次。同样,也没有办法将6表示为两个或三个唯一质数之和。

情况– 3说明:10不是质数,但10可以表示为10 = 3 + 7或10 = 2 + 3 +5。在这两个表达式中,每个质数仅使用一次。

1 个答案:

答案 0 :(得分:0)

在不使用任何数学技巧的情况下(不确定是否存在任何技巧...作为数学家,我想在这里会有更多的见识),您将必须遍历所有可能的求和。因此,您肯定需要遍历所有可能的素数,因此,我建议第一步是找到最多10 ^ 5的所有素数。基本的(Eratosthenes筛)[https://en.wikipedia.org/wiki/Sieve_of_Eratosthenes]可能已经足够了,尽管如今存在更快的筛子。我知道您的问题与语言无关,但是您可以将以下内容视为此类筛的矢量化伪代码。

import numpy as np

def sieve(n):
    index = np.ones(n+1, dtype=bool)
    index[:2] = False
    for i in range(2, int(np.sqrt(n))):
        if index[i]:
            index[i**2::i] = False
    return np.where(index)[0]

还有其他一些简单的优化方法,但是为简单起见,我们假设我们有一个数组index,其中的索引与该数字是否为质数完全对应。我们从每个数字为质数开始,将0和1标记为非质数,然后对于每个质数,我们发现将其所有倍数标记为非质数。最后的np.where()仅返回索引对应于True的索引。

从那里开始,我们可以考虑一种实际解决您的问题的递归算法。请注意,您可能可能需要大量不同的素数。数字26是4个不同素数的总和。它也是3和23的总和。由于检查4个素数要比检查2个素数贵,因此我认为从检查最小数开始是合理的。

在这种情况下,我们要这样做的方法是定义一个辅助函数,以找到一个数字是否恰好是k个素数的和,然后依次测试k的辅助函数从1到可能的最大值附加数是。

primes = sieve(10**5)

def sum_of_k_primes(x, k, excludes=()):
    if k == 1:
        if x not in excludes and x in primes:
            return (x,)+excludes
        else:
            return ()
    for p in (p for p in primes if p not in excludes):
        if x-p < 2:
            break
        temp = sum_of_k_primes(x-p, k-1, (p,)+excludes)
        if temp:
            return temp
    return ()

首先,我们检查k为1的情况(这是递归的基本情况)。这与询问x是否为质数,是否不属于我们已经发现的质数之一(元组excludes,因为您需要唯一性)相同。如果k至少为2,则执行其余代码。我们会检查所有可能关心的素数,如果得到不可能的结果,则尽早停止(列表中的素数不小于2)。我们递归地为较小的k调用相同的函数,如果成功,我们会将结果传播到调用堆栈中。

请注意,我们实际上返回的是唯一素数附加元素的最小元组。如果您希望答案指定为"NO",则此字段为空,否则,您可以轻松提出答案的答案。{p}

"YES"

对于代码的其余部分,我们存储到给定点的所有素数的部分和(例如,素数为2、3、5的部分和为2、5、10)。这使我们可以轻松地检查加数的最大可能数量。该函数只是顺序检查partial = np.cumsum(primes) def max_primes(x): return np.argmax(partial > x) def sum_of_primes(x): for k in range(1, max_primes(x)+1): temp = sum_of_k_primes(x, k) if temp: return temp return () 是否为素数,是否为2个素数,3个素数之和,等等。...

作为一些示例输出,我们有

x

乍一看,我认为缓存一些中间值可能会有所帮助,但我不相信会使用相同的参数两次调用辅助函数。可能有一种方法可以使用动态编程来执行大致相同的操作,但在具有最少计算量的表中可以防止使用递归进行任何重复的工作。我必须考虑更多。

就您的老师所期望的确切输出以及需要使用的编码语言而言,这取决于您。希望这可以在算法方面有所帮助。