一个数字,因为它是素数部分

时间:2013-01-08 15:52:24

标签: c++ algorithm primes

我必须打印表示给定数字的方式,因为它是素数部分。

让我澄清一下:假设我得到了这个数字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

3 个答案:

答案 0 :(得分:9)

动态编程是你的朋友。

考虑数字27。

如果7有5个结果,20有732个结果,那么你知道27个结果至少有(732 * 5)。您可以使用预先计算的两个变量系统(1 + 26,2 + 25 ......等)。您不必重新计算25或26,因为您已经完成了它们。

答案 1 :(得分:3)

您要搜索的概念是数字的“主要分区”。数字的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指出了一个动态编程解决方案。

我在my blog更详细地讨论了主要分区,包括生成计数和列表的源代码。

答案 2 :(得分:0)

这是一个有效的实现,它使用动态编程,如corsiKa建议,但不使用他描述的算法。

简单地说:如果n可以通过k个不同的路径(包括单步路径,如果它存在),p是素数,那么我们构建{{1}将k附加到n+p的所有路径的p路径。考虑所有这些n将生成n < N的有效路径的详尽列表。所以我们只是总结了所发现的路径数量。

N

用大整数类型替换typedef #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; } 留给读者练习。