簡體   English   中英

一個數字,因為它是素數部分

[英]A number as it's prime number parts

我必須打印代表給定數字的方式,因為它是素數部分。

讓我澄清一下:讓我說我得到了這個數字7.現在,首先,我必須找到所有小於7的素數,即2,3和5.現在,我可以用多少種方法總結這些數字(我可以使用我想要的一個數字),以便結果等於7? 例如,數字7有五種方式:

2 + 2 + 3
2 + 3 + 2
2 + 5
3 + 2 + 2
5 + 2

我完全迷失了這項任務。 首先,我想我會制作一系列可用的元素,如:{2,2,2,3,3,5}(7/2 = 3,所以2必須出現三次。相同的是3,得到兩個出現次數)。 之后,循環遍歷數組並選擇一個'leader'來確定我們在數組中的距離。 我知道解釋很可怕,所以這里是代碼:

#include <iostream>
#include <vector>

int primes_all[25] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97};

int main()
{
    int number;
    std::cin >> number;

    std::vector<int> primes_used;

    for(int i = 0; i < 25; i++) {
        if(primes_all[i] < number && number-primes_all[i] > 1) {
            for(int k = 0; k < number/primes_all[i]; k++)
                primes_used.push_back(primes_all[i]);
        }
        else break;
    }

    int result = 0;

    for(size_t i = 0; i < primes_used.size(); i++) {
        int j = primes_used.size()-1;
        int new_num = number - primes_used[i];

        while(new_num > 1 && j > -1)
        {
            if(j > -1) while(primes_used[j] > new_num && j > 0) j--;

            if(j != i && j > -1) {
                new_num -= primes_used[j];

                std::cout << primes_used[i] << " " << primes_used[j] << " " << new_num << std::endl;
            }

            j--;
        }

        if(new_num == 0) result++;
    }

    std::cout << result << std::endl;

    system("pause");
    return 0;
}

這根本行不通。 僅僅因為它背后的想法是錯誤的。 這是關於限制的一些細節:

  • 時間限制:1秒
  • 內存限制:128 MB

此外,可以給出的最大數字是100.這就是為什么我將素數數組設置為低於100.隨着給定數字變大,結果變得非常快,稍后將需要BigInteger類,但這不是問題。

一些結果已知:

Input    Result

7        5
20       732
80       10343662267187

所以...任何想法? 這是一個組合問題嗎? 我不需要代碼,只需要一個想法。 我仍然是C ++的新手,但我會管理


請記住,3 + 2 + 2不同於2 + 3 + 2.此外,如果給定的數字本身是素數,則不會計算。 例如,如果給定的數字是7,則只有這些總和有效:

2 + 2 + 3
2 + 3 + 2
2 + 5
3 + 2 + 2
5 + 2
7 <= excluded

動態編程是你的朋友。

考慮數字27。

如果7有5個結果,20有732個結果,那么你知道27個結果至少有(732 * 5)。 您可以使用預先計算的兩個變量系統(1 + 26,2 + 25 ......等)。 您不必重新計算25或26,因為您已經完成了它們。

您要搜索的概念是數字的“主要分區”。 數字的S分區是一種添加數字以達到目標的方式; 例如,1 + 1 + 2 + 3是7的分區。如果所有加數都是素數,則該分區是主分區。

我認為你的例子是錯的。 數字7通常被認為具有3個主要分區:2 + 2 + 3,2 + 5和7.加數的順序無關緊要。 在數論中,計算主要分區的函數是kappa,所以我們會說kappa(7)= 3。

kappa的通常計算分兩部分完成。 第一部分是計算數字素因子之和的函數; 例如,42 = 2·3·7,所以sopf(42)= 12。 注意,sopf(12)= 5,因為總和僅超過數字的不同因子,因此即使12 = 2·2·3,在總和的計算中也只包括一個2。

考慮到sopf,有一個很長的公式來計算kappa; 我會用LaTeX形式給它,因為我不知道如何在這里輸入它:\\ kappa(n)= \\ frac {1} {n} \\ left(\\ mathrm {sopf}(n)+ \\ sum_ { j = 1} ^ {n-1} \\ mathrm {sopf}(j)\\ cdot \\ kappa(nj)\\ right)。

如果您真的想要一個分區列表,而不僅僅是計數,那么@corsiKa指出了一個動態編程解決方案。

我在博客上更詳細地討論了主要分區,包括生成計數和列表的源代碼。

這是一個有效的實現,使用動態編程,如corsiKa建議,但不使用他描述的算法。

簡單地說:如果n可以通過k不同的路徑(包括單步路徑,如果它存在),並且p是素數,那么我們通過將p附加到n所有路徑來構造到n+pk路徑。 考慮到所有這樣的n < N將產生到N的有效路徑的詳盡列表。 所以我們只是總結了如此發現的路徑數量。

#include <iostream>

int primes_all[] = {2, 3, 5, 7, 11, 13, 17, 19, 23, 29, 31, 37, 41, 43, 47, 53, 59, 61, 67, 71, 73, 79, 83, 89, 97};

const int N_max = 85;
typedef long long ways;
ways ways_to_reach_N[N_max + 1] = { 1 };

int main()
{
    // find all paths
    for( int i = 0; i <= N_max; ++i ) {
        ways ways_to_reach_i = ways_to_reach_N[i];

        if (ways_to_reach_i) {
            for( int* p = primes_all; *p <= N_max - i && p < (&primes_all)[1]; ++p ) {
                ways_to_reach_N[i + *p] += ways_to_reach_i;
            }
        }
    }

    // eliminate single-step paths
    for( int* p = primes_all; *p <= N_max && p < (&primes_all)[1]; ++p ) {
        --ways_to_reach_N[*p];
    }

    // print results
    for( int i = 1; i <= N_max; ++i ) {
        ways ways_to_reach_i = ways_to_reach_N[i];

        if (ways_to_reach_i) {
            std::cout << i << " -- " << ways_to_reach_i << std::endl;
        }
    }

    return 0;
}

用大整數類型替換typedef ways留給讀者練習。

暫無
暫無

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

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