Prime Generator算法

时间:2013-12-23 12:52:59

标签: c algorithm primes

我一直在努力解决素数生成器算法的SPOJ问题。

这是问题

  

彼得想为他的密码系统生成一些素数。救命   他!你的任务是生成两个给定的所有素数   数字!

     

输入

     

输入以单行中的测试用例数t开头   (T< = 10)。在接下来的每一行中,有两个数字m和n(1   < = m< = n< = 1000000000,n-m< = 100000)以空格分隔。

     

输出

     

对于每个测试用例,打印所有素数p,使得m <= p <= n,   每行一个数字,用空行分隔的测试用例。

这很容易,但在线判断显示错误,我没有得到“测试用例”的问题以及为什么要使用1000000范围。

这是我的代码。

#include<stdio.h>

main()
{
int i, num1, num2, j;
int div = 0;
scanf("%d %d", &num1, &num2);
for(i=num1; i<=num2; i++)
  {
    for(j=1; j<=i; j++)
    {
      if(i%j == 0)
      {
        div++;
      }
    }
    if(div == 2)
    {
     printf("%d\n", i);
    }
    div = 0;
  }
  return 0;
}

8 个答案:

答案 0 :(得分:2)

我无法评论alogirthm以及100000数字范围是否允许优化,但是代码无效的原因是因为它似乎没有正确解析输入。输入将类似于:

2
123123123 123173123 
987654321 987653321

这是第一行将给出每行输入的输入组数,然后是一组输入。你的程序一目了然,看起来只是在读第一行寻找两个数字。

我认为在线判断只是在寻找正确的输出(可能是合理的运行时间?)所以如果你纠正了写入输入,无论你的算法效率低下(其他人已开始评论),它都应该有效。

答案 1 :(得分:1)

要查找m,n 1 <= m <= n <= 1000000000, n-m<=100000之间的素数,首先需要准备从2到sqrt(1000000000) < 32000的核心素数。简单的连续sieve of Eratosthenes绰绰有余。 (已经筛选了核心 bool sieve[] 数组(a related C code is here),确实创建一个包含核心素数的单独数组 int core_primes[] ,从筛子阵列中浓缩,以易于使用的形式,因为你有多个偏移段可以筛选它们。)

然后,对于每个给定的单独片段,只需使用制备的核心质粒筛选它。 100,000足够短,没有 evens 它只有50,000 赔率。您可以使用一个预先分配的数组,并为每个新对m,n调整寻址方案。数组中的 i 条目将代表 o + 2i 的数字,其中 o 是某个段的奇数开始。

另见:

关于术语的说法:这不是“分段筛”。这指的是一个接一个地对连续段进行筛分,随着时间的推移更新核心素数列表。这里的上限是事先已知的,其平方根非常小。

相同的核心质数用于筛选每个单独的偏移段,因此可以更好地描述为Eratosthenes的“偏移”筛。对于每个被筛分的区段,当然只需要使用不大于其上限的平方根的核心素数;但核心素数是更新,而每个这样的偏移段被筛选(更新核心素数是“分段”筛子的签名特征。)

答案 2 :(得分:1)

输入以单行中的测试用例数t开始(t <= 10) 你的程序中没有测试用例。 这是不对的 抱歉我的英文

2 - //the number of test cases
1 10 - // numbers n,m
3 5 - // numbers

您的程序只能在第一行使用。

答案 3 :(得分:1)

#include <stdio.h>
#include <math.h>
int main()
{
    int test;
    scanf("%d",&test);
    while(test--)
    {
        unsigned int low,high,i=0,j=2,k,x=0,y=0,z;
        unsigned long int a[200000],b[200000];
        scanf("%d",&low);
        scanf("%d",&high);
        for(i=low;i<=high;i++)
            a[x++]=i;
        for(i=2;i<=32000;i++)
            b[y++]=i;
        i=0;
        while(b[i]*b[i]<=high)
        {
            if(b[i]!=0)
            {
                k=i;
                for(;k<y;k+=j)
                {
                    if(k!=i)
                    {
                        b[k]=0;
                    }
                }
            }
            i+=1;j+=1;
        }
            for(i=0;i<y;i++)
            {
                if(b[i]!=0 && (b[i]>=low && b[i]<=sqrt(high)))
                    printf("%d\n",b[i]);
            }
            int c=0;
            for(i=0;i<y;i++)
            {
                if(b[i]!=0 && (b[i]>=1 && b[i]<=sqrt(high)))
                    b[c++]=b[i];
            }
            int m=a[0];
            for(i=0;i<c;i++)
            {
                z=(m/b[i])*b[i];k=z-m;
                if(k!=0)
                    k += b[i];
                for(;k<x;)
                {
                    if(a[k]!=0)
                    {
                        a[k]=0;
                    }
                    k+=b[i];
                }
            }
            for(i=0;i<x;i++)
            {
                if(a[i]!=0 && (a[i]>=2 && a[i]<=(high)))
                    printf("%d\n",a[i]);
            }
        printf("\n");
    }
    return 0;
}

答案 4 :(得分:0)

对于如此小的数字,您只需搜索1到1000000000之间的所有素数。

获取62.5 mByte的RAM来创建一个二进制数组(每个奇数用一位,因为我们已经知道没有偶数(2除外)是素数。)

将所有位设置为0表示它们是素数,而不是使用Sieve of Eratosthenes将位设置为非素数的所有数字中的1。

筛选一次,存储结果列表。

答案 5 :(得分:0)

你的上限是10 ^ 9。 Eratosthenes的筛子是 O(N loglogN),这对于那个界限太大了。

以下是一些想法:

更快的素性测试

一个天真解决方案的问题,你循环范围[i,j]并检查每个数字是否为素数是需要 O(sqrt(N))来测试一个数字如果处理好几个案例,那就太过分了。

但是,您可以尝试更智能的素性测试算法。 Miller-Rabin N 的位数的多项式,对于N <= 10 ^ 9,您只需要检查a = 2,7和61。

请注意,我实际上没有尝试过这个,所以我不能保证它会起作用。

分段筛

正如@KaustavRay所提到的,你可以使用分段筛。根本的想法是,如果数字N是复合的,那么它具有最多为sqrt(N)的素数除数。

我们使用Eratosthenes筛选算法找到低于32,000的素数(大致为sqrt(10 ^ 9)),然后对于[i,j]范围内的每个数字,检查是否有任何低于32,000的素数除以它。

prime number theorem约有一个在log(N)中的数字是素数,它足够小以便在时间限制内挤压。

答案 6 :(得分:0)

int num; 
bool singleArray[100000]; 
static unsigned long allArray[1000000]; 
unsigned long nums[10][2]; 

unsigned long s;       
long n1, n2;
int count = 0; 
long intermediate; 


scanf("%d", &num);

for(int i = 0; i < num; ++i) 
{
    scanf("%lu", &n1);  
    scanf("%lu", &n2); 
    nums[i][0] = n1;   
    nums[i][1] = n2;   
}


for(int i = 0; i < 100000; ++i)  
{
    singleArray[i] = true;
}

for(int i = 0; i < num; ++i) 
{
    s = sqrt(nums[i][1]);
    for(unsigned long k = 2; k <= s; ++k)  
    {
        for (unsigned long j = nums[i][0]; j <= nums[i][1]; ++j) 
        {
            intermediate = j - nums[i][0];
            if(!singleArray[intermediate]) 
            {
                continue;
            }
            if((j % k == 0 && k != j) || (j == 1))      
            {
                singleArray[intermediate] = false;
            }
        }
    }


    for(unsigned long m = nums[i][0]; m <= nums[i][1]; ++m) 
    {
        intermediate = m - nums[i][0];
        if(singleArray[intermediate])  
        {
            allArray[count++] = m;
        }
    }

    for(int p = 0; p < (nums[i][1] - nums[i][0]); ++p)
    {
        singleArray[p] = true;
    }
 }


for(int n = 0; n < count; ++n)
{
    printf("%lu\n", allArray[n]);
}

}

答案 7 :(得分:0)

#include <iostream>
using namespace std;

int main() {

    // your code here
unsigned long int m,n,i,j;int N;
cin>>N;
for(;N>0;N--)
{
    cin>>m>>n;
    if(m<3)
        switch (n)
        {
            case 1: cout<<endl;continue;
            case 2: cout<<2<<endl;
                    continue;
            default:cout<<2<<endl;m=3;
        }
    if(m%2==0) m++;        
    for(i=m;i<=n;i+=2)
    {  
        for(j=3;j<=i/j;j+=2)
            if(i%j==0)
                {j=0;break;}
        if(j)
        cout<<i<<endl;
    }
        cout<<endl;

}return 0;}