【问题标题】:Can you tell me why this generates time limit exceeded in spoj(Prime Number Generator)你能告诉我为什么这会在 spoj(Prime Number Generator) 中产生超过时间限制
【发布时间】:2011-01-05 10:03:10
【问题描述】:
#include<iostream>
#include<string.h>
#include<math.h>
using namespace std;    

bool prime[1000000500];
void generate(long long end)
{
    memset(prime,true,sizeof(prime));
    prime[0]=false;
    prime[1]=false;

        for(long long i=0;i<=sqrt(end);i++)
        {
         if(prime[i]==true)
         {
             for(long long y=i*i;y<=end;y+=i)
             {
                 prime[y]=false;
             }
         }
        }
}

int main()
{
    int n;
    long long b,e;
    scanf("%d",&n);
    while(n--)
    {
        cin>>b>>e;
        generate(e);
        for(int i=b;i<e;i++)
        {
            if(prime[i])
                printf("%d\n",i);
        }
    }
    return 0;
}

这是我的 spoj prime 生成器代码。
尽管它会生成与另一个接受的代码相同的输出..

【问题讨论】:

    标签: c++ generator primes


    【解决方案1】:

    您不需要筛选每个数字直到最后一个数字。这很愚蠢。只对开始和结束数字之间的范围进行操作。 (部分筛子)

    我已经在 Python 中解决了这个问题,这就是我最终设法做到的方式。我还开始计算所有素数,直到潜在最大值的平方根 1000000000。这只是 31623,所以不需要很长时间。

    从此列表中使用这些数字直到当前案例最大值的平方根来筛选当前案例。

    【讨论】:

      【解决方案2】:

      这个问题需要一个 Segmented Sieve 实现。一个简单的 Eratosthenes 分段筛可以很容易地用 C/C++ 用大约 50-60 行代码进行编程。 如果你实现了一个分段筛,你只需要为问题中提到的最大大小的段分配内存。

      还有一些其他的优化可以提供一些帮助。我将列出我在解决方案中所做的:

      • 检查只有素数的倍数,直到最大数的平方根。

      • 可以预先计算所有素数的查找数组,直到最大可能数的平方根,即 sqrt(10^9) 并添加到源代码中。此问题的 SPOJ 源代码大小限制为 50000 字节,添加此查找数组仍符合此大小限制。

      • 删除倍数时,从 y=i*i 开始,但只检查 i 的奇数倍数。

      通过这些优化,我的 C++ 代码运行时间约为 0.05 秒。即使没有这些 优化我认为分段筛应该被接受。希望这会有所帮助。

      【讨论】:

        【解决方案3】:

        一个让它更快的简单技巧是从 for 循环中取出 sqrt

        double sqrtOfEnd = sqrt(end);
        for(long long i=0; i<=sqrtOfEnd; i++)
        {
          ...
        

        您无需在每个循环中重新计算平方根。
        正如其他人指出的那样,这可能还不够,您可能需要考虑其他寻找素数的方法。

        【讨论】:

          【解决方案4】:

          由于您需要从多个序列中输出素数,因此可能会保留先前筛选的结果,仅根据需要继续填写表格的其余部分?

          【讨论】:

          • 要存储的数字很多。计算素数不是问题,但存储它们可能是。
          【解决方案5】:

          您需要让它更快 - 对于范围 999900000-1000000000 等测试用例,Eratosthene 的筛分算法太慢了。您可以尝试其他替代方案,并会产生更好的结果。

          附言。当然我不会告诉你这些是什么。做你的作业。 :P

          【讨论】:

          • 好吧,我没有发布这个问题,直到我非常绝望......所以如果你知道我可以如何优化它?请告诉。
          • 有许多素数测试可以根据您的目的进行调整(请参阅 Miller-Rabin、Agrawal 和 Biswas、Bernstein 在“证明基本四次随机时间中的素数”)以及其他方法素数生成(阿特金筛法)。我敢肯定还有其他的,因为它是一个相对“热门”的研究课题。
          • Eratosthene 的筛分算法并不算太慢。只在测试范围内而不是在 0 到 1000000000 的整个范围内运行的修改版本就可以了。
          • @nakedfanatic:你的意思是,分段的 Eratosthene 的筛子不会太慢。这和传统的筛算法不一样,实现起来肯定也没有那么容易。我打算避免提及它,但是 w/e。 :)
          • 没错,我非常依赖 Python 的扩展切片表示法。我预计在 C++ 中实现会更痛苦。
          【解决方案6】:

          @nakedfantaic 没错!

          #include <cstdio>
          #include <cmath>
          
          unsigned int numbers[3500], len;
          
          inline bool prime(unsigned int x)
          {
              unsigned int i, last = sqrt(x);
              for (i = 2; i <= last; i++) {
                  if (!(x % i)) {
                      return 0;
                  }
              }
              return 1;
          }
          
          void generate()
          {
              for (unsigned int i = 2; i < 32000; i++) {
                  if (prime(i)) {
                      numbers[len++] = i;
                  }
              }
          }
          
          inline bool process(unsigned long x)
          {
              unsigned int i, last = sqrt(x);
              for (i = 0; i < len && numbers[i] <= last; i++) {
                  if (!(x % numbers[i])) {
                      return 0;
                  }
              }
              return 1;
          }
          
          int main()
          {
              int tests;
              unsigned long begin, end;
              generate();
              scanf("%d", &tests);
              while (tests-- > 0) {
                  scanf("%u %u", &begin, &end);
                  if (begin == 1) {
                      begin++;
                  }
                  while (begin <= end) {
                      if (process(begin)) {
                          printf("%u\n", begin);
                      }
                      begin++;
                  }
                  printf("\n");
              }
              return 0;
          }
          

          http://pastebin.com/G5ZRd5vH

          【讨论】:

          • 这是试用部门;它比@nakedfanatic 提出的 Eratosthenes 筛子慢得多。
          【解决方案7】:

          我可以在 python 3.4 方面提供帮助,我的 spoj(prime generator) 工作代码是这样的:

          import math
          primes = [True for i in range(int(math.sqrt(1000000000))+1)]
          tes = int(math.sqrt(math.sqrt(1000000000)*2))+1
          for i in range(2,tes):
              if primes[i]:
                  for z in range(i*i,int(math.sqrt(1000000000))+1,i):
                      primes[z] = False
          for z in range(int(input().strip())):
              m,n = map(int,input().strip().split())
              if n == 1:
                  print('')
                  continue
              elif m == 1:
                  m += 1
              ans = [True for i in range(n-m+1)]
              for i in range(2,int(math.sqrt(1000000000))+1):
                  if primes[i]:
                      if i > n:
                          break
                      num = m//i
                      if num*i != m:
                          num += 1
                      if num < 2:
                          num = 2
                      while num*i <= n:
                          ans[num*i-m] = False
                          num += 1
              for i in range(n-m+1):
                  if ans[i]:
                      print(i+m)
              print('')
          

          【讨论】:

            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 2021-09-30
            • 1970-01-01
            • 2016-04-07
            • 1970-01-01
            • 2020-04-10
            • 2015-09-12
            • 2016-10-29
            相关资源
            最近更新 更多