【问题标题】:A number as it's prime number parts一个数字,因为它是质数部分
【发布时间】:2013-01-08 15:52:24
【问题描述】:

我必须打印出可以表示给定数字的方式的数量,因为它是质数部分。

让我澄清一下:假设我得到了这个数字 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 次。3 也是如此,它有两个发生)。之后,遍历数组并选择一个“领导者”来确定我们在数组中的距离。我知道这个解释很糟糕,所以这里是代码:

#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 + 2 + 2 是否被认为与 2 + 2 + 3 不同?
  • 是的。 3 + 2 + 2 != 2 + 3 + 2 != 2 + 2 + 3
  • 这与哥德巴赫猜想有关。

标签: c++ algorithm primes


【解决方案1】:

动态编程是你的朋友。

考虑数字 27。

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

【讨论】:

  • 并且不要在递归中执行此操作,“因为您已经这样做了”,而是在循环中开始为 1 构建总和,然后为 2 等等,直到您为您的目标号码建立总和。通过重用旧值来计算新值 + 在每个步骤中添加基本情况“单个素数”。您不需要可以使用的一组数字 (primes_used)
  • 这超出了我的想象。你能澄清一下吗?
  • 这通常不会像这里建议的那样工作;您忽略了素数的身份,这些很重要,因为不同的顺序很重要。
  • 您的意思是“至少 732 * 5”个结果吗?
  • 我是认真的吗?不,不,我没有。我应该放它是因为它更正确,是的,是的,我应该放它。 =)
【解决方案2】:

您正在搜索的概念是数字的“主要分区”。一个数的 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(n-j)\right)。

如果你真的想要一个分区列表,而不仅仅是计数,@corsiKa 指出了一个动态编程解决方案。

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

【讨论】:

  • 这是一些很酷的信息。但是,就我而言,3 + 2 + 2 不同于 2 + 3 + 2 不同于 2 + 2 + 3
  • 这不是正常的方式。首先,您应该与您的导师明确说明您的要求。然后,如果你真的想要你所说的,谷歌搜索“重复的主分区”或“不同的主分区”。在任何情况下,请注意您的 7 的主要分区示例省略了数字 7 本身,这是素数,因此通过您的方法,有六种方法,而不是五种方法来制作 7 的分区。
  • 对不起,我以为我提到了。我将编辑问题的描述。感谢您指出路径,寿:D
  • 这是一个 SPOJ 问题吗?或者其他一些网络编码网站?如果是这样,请提供原始问题的链接。如果是作业,请发布作业链接。
  • 这是家庭作业,作业出自我的导师之口,从未出现在纸上,而且是芬兰语。我尽可能地描述了这个问题
【解决方案3】:

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

简单地说:如果n 可以通过k 不同的路径(包括单步路径,如果存在的话)到达,并且p 是素数,那么我们通过附加构造kn+p 的路径pn 的所有路径。考虑到所有这些n &lt; 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 替换为大整数类型留给读者作为练习。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2017-11-25
    • 1970-01-01
    • 1970-01-01
    • 2010-11-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多