【问题标题】:Prime number generator doesn't work for small numbers素数生成器不适用于小数
【发布时间】:2018-12-09 22:34:39
【问题描述】:

2 天以来,我一直在努力解决 SPOJ 的 PRIME1 问题。我设法编写了一个适用于大数字的程序,但我不明白为什么它会在开始范围(通常是 1-11)中显示如此混乱的数字。我正在使用 Eratosthenes 的分段筛。 SPOJ link

问题来了:

输入

输入以单行中的测试用例数量 t (t

输出

对于每个测试用例打印所有质数 p 使得 m

还有我的代码:

#include <bits/stdc++.h>
using namespace std;

#define MAX         1000000000
#define MAX_SQRT    sqrt(MAX)

vector<bool> is_prime(MAX_SQRT, true);

void simpleSieve(int limit, vector<int>& primes)
{
    for(int p=2; p*p<=limit; p++) {
        if(is_prime[p] == true) {
            for(int i=p*p; i<=limit; i+=p)
                is_prime[i] = false;
        }
    }
    for(int i=2; i<=limit; i++) {
        if(is_prime[i]) primes.push_back(i);
    }
}

void segmentedSieve(int left, int right)
{
    int range = floor(sqrt(right)) + 1;
    vector<int> primes;
    simpleSieve(range, primes);

    int n = right - left + 1;

    bool sieve[n];
    memset(sieve, true, sizeof(sieve));

    for (int i = 0; i<primes.size(); i++) {

        int low = floor(left/primes[i]) * primes[i];
        if(low < left)
            low += primes[i];

        for(int a=low; a<=right; a+=primes[i]) {
            sieve[a - left] = false;
        }
    }
    for(int i=left; i<=right; i++)
        if(sieve[i - left])   cout << i << "\n";
}

int main()
{
    int t;
    cin >> t;
    while(t--) {
        int left, right;
        cin >> left >> right;
        segmentedSieve(left, right);
    }
    return 0;
}

我尝试对开头部分进行硬编码,但它会因输入而异。

【问题讨论】:

  • bool sieve[n] 不是有效的C++。这是一个Variable Length Array (VLA),它只是一些编译器的扩展。我看到你已经在使用std::vector。您还应该将它用于sieve
  • 我之前一直在使用它,但是由于一些实现问题我将std::vector替换为bool数组。虽然现在使用矢量它可以正常工作,所以我已经改变了它。谢谢!
  • 第一次调用 simpleSieve 基本上完成了这项工作。可能问题出在range的计算上。

标签: c++ c++11 primes sieve-of-eratosthenes


【解决方案1】:

首先打印使用 simpleSieve 生成​​的大于左的素数。
另外,1 不是素数,所以我们会在打印其他素数时跳过它:

for (int i = 0; i<primes.size(); i++) {
    if (primes[i] >= left)
        cout << primes[i] << "\n";
}

for(int i=left; i<=right; i++){
    if (i == 1){
        continue;
    }
    if(sieve[i - left])   cout << i << "\n";
}
cout << "\n";  //empty line before next testcase starts

【讨论】:

  • 见输入 3 5149 170。对于从 1 开始的更大范围的开始部分,此修复有所帮助,但 +primes[i] 导致它避免了关键的筛分部分(我猜)。我认为问题可能在于将已筛选的数字保存到向量中(来自 3 5 输入的输出 4 表明了这一点)。
  • 一夜之后,我回到了这个问题,并注意到应用修复后究竟是什么问题。输出始终显示从 right 开始的 2 个连续数字(显然,这些数字被设置为 true)。还是不知道怎么解决。
  • @KacperPaluch 我已经修改了代码,这肯定可以工作。你的代码很完美。我所做的只是打印 simpleSieve 生成​​的素数(如果它们在给定范围内)。
猜你喜欢
  • 2014-05-05
  • 2014-11-10
  • 2020-03-15
  • 2017-03-29
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多