簡體   English   中英

如何找到n作為塵埃素數的和(當n是偶數時)

[英]How to find n as sum of dustinct prime numbers (when n is even number)

此問題為您提供一個小於或等於100000(10 ^ 5)的正整數。 您必須找出該號碼的以下內容:

一世。 是素數嗎? 如果它是質數,則打印是。

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。在這兩個表達式中,每個質數僅使用一次。

在不使用任何數學技巧的情況下(不確定是否存在……您可能會想作為一個數學家,在這里我將有更多的見識),您將不得不遍歷所有可能的求和。 因此,您肯定需要遍歷所有可能的素數,因此,我建議第一步是找到最多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" ,則此字段為空,但否則,您可以輕松提出為什么回答"YES"

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、5,部分和將為2、5、10)。 這使我們可以輕松地檢查加數的最大可能數量。 該函數只是順序地檢查x是否為素數,是否為2個素數,3個素數之和,等等。

作為一些示例輸出,我們有

>>> sum_of_primes(1001)
(991, 7, 3)

>>> sum_of_primes(26)
(23, 3)

>>> sum_of_primes(27)
(19, 5, 3)

>>> sum_of_primes(6)
()

乍一看,我認為緩存一些中間值可能會有所幫助,但我不相信會使用相同的參數兩次調用輔助函數。 可能有一種方法可以使用動態編程來執行大致相同的操作,但在具有最少計算量的表中可以防止使用遞歸進行任何重復的工作。 我不得不考慮更多。

至於您的老師所期望的確切輸出以及需要使用的編碼語言,這將取決於您。 希望這可以在算法方面有所幫助。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM