【问题标题】:How can I reduce the runtime?如何减少运行时间?
【发布时间】:2015-06-02 00:26:32
【问题描述】:

这是我要解决的问题的链接:http://acm.timus.ru/problem.aspx?space=1&num=1086

这是我的方法:

#include <stdio.h>
#include <math.h>

int main()
{
    int n, i, m, p;

    scanf("%d", &n);

    for(i = 0; i < n; i++)
    {
        scanf("%d", &m);

        p = find_prime(m);
        printf("%d\n", p);
    }

    return 0;
}

int find_prime(int a)
{
    int i, p = 1, t, prime[15000], j;
    prime[0] = 2;

    for(i = 0; i < a; )
    {
        if(p == 2)
        {
            p++;
        }else
        {
            p = p + 1;
        }
        t = 0;
        for(j = 0; prime[j] <= sqrt(p); j++)
        {
            if(p%prime[j] == 0 && p != 2)
            {
                t = 1;
                break;
            }
        }
        if(t != 1)
        {
            i++;
            prime[i] = p;
        }
    }

    return p;
}

我知道算法很好,它会产生正确的答案。但我总是得到“超过时间限制”。我无法将运行时下载到 2 秒。它始终等于 2.031 秒。我尝试了一些其他方法,例如,我遍历所有数字,直到找到第 m 个素数,我尝试跳过大于 2 的偶数,但我仍然得到 2.031 秒。

我该怎么办?

【问题讨论】:

  • 您可以使用sieve of Erastosthenes
  • 您认为if(p == 2) { p++; }else { p = p + 1; } 的两个分支之间的行为差​​异是什么?对我来说,看起来好像p 增加了 1,而不管其初始值如何。 —— 而且我看到Ed Heal 在他的not really an answer 中指出了这一点。
  • 由于等待用户输入一些数字序列是海量的,时间上,与实际执行相比似乎不切实际,将注意力集中在 find_prime() 函数的执行时间上
  • 在调用 scanf()(或任何该系列函数)时,代码应始终检查返回值(而不是参数值)以确保操作成功

标签: c algorithm primes number-theory


【解决方案1】:

您的素数缓冲区不需要是每次都重新计算的局部变量。

您可以尝试memoize,方法是将缓冲区存储在全局范围内,并使用全局计数器来跟踪到目前为止您已经计算了多少素数以及请求的最大数是哪个数。

如果向您请求的下一个数字小于上一个最大值,您应该回退到相应的预先计算的数字。如果下一个数字大于前一个最大值,请将其设为新的最大值 - 并尝试从上次停止的位置开始计算。

【讨论】:

  • 为什么不预先计算所有小于 15000 的素数?他有 64 MB 的内存可供使用。这应该足够了。
  • @Seamus 我故意描述了一个通用的解决方案。当然,对于我们正在讨论的大小,您关于预计算的建议是完全有效的(并且很可能会更高效)。在现实世界的场景中,这两种技术的组合可能是可行的。
  • @seamus,这不会花很多时间吗?并且我输入的数字不能大于 15000,而不是素数。
  • @lucid.dreamer 无论如何,您都是在运行时计算所有这些数字。只需预先计算一次并将它们硬编码到您的文件中,不会比这花费更长的时间。
  • @lucid.dreamer 作为一般参考,我用了 60 毫秒来计算一个 erthostene 的筛子,直到 163,841(#15,000 素数),并在 python 中简单地实现了算法。所以,不,它不会花费这么多时间。
【解决方案2】:

删除

  if(p == 2)
    {
        p++;
    }else
    {
        p = p + 1;
    }

替换成

p++

【讨论】:

  • 我试过了。这对我没有任何好处。所以我想如果我可以跳过明显非素数的整数,可能会花费更少的时间。
【解决方案3】:

据我了解,

问题是找到下一个大于所有先前输入数字之和的素数。

这意味着有一定的期望。

1) the sum of the prior input numbers is available in find_prime(). 
2) for simplification, the last found prime number is available in find_prime().  

这些期望都没有实现。

然后在 find_prime() 中的堆栈上有那个 60,000 字节的数组。

建议将其移至文件全局位置并包含“静态”修饰符。

将先前的输入总和移动到文件全局位置,因此它始终可用。

对于整体速度,

首先计算数组中的所有素数,从而用素数填充数组。那么

1) add new input to sum, 
2) index into array using sum. 
3) return value found in array.

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2020-06-13
    • 1970-01-01
    • 1970-01-01
    • 2016-07-24
    • 2021-11-28
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多