Prime Generator Algorithm

只愿长相守 提交于 2019-12-04 14:32:02

I can't comment on the alogirthm and whether the 100000 number range allows optimisations but the reason that your code is invalid is because it doesn't seem to be parsing the input properly. The input will be something like:

2
123123123 123173123 
987654321 987653321

That is the first line will give the number of sets of input you will get with each line then being a set of inputs. Your program, at a glance, looks like it is just reading the first line looking for two numbers.

I assume the online judge is just looking for the correct output (and possibly reasonable running time?) so if you correct for the right input it should work no matter what inefficiencies are in your algorithm (as others have started commenting on).

user5450071

The input begins with the number t of test cases in a single line (t<=10) you haven't got test cases in your programm. Its wrong And sorry for my English

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

Your programm will work only in first line.

#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;
}
Will Ness

To find primes between m,n where 1 <= m <= n <= 1000000000, n-m<=100000, you need first to prepare the core primes from 2 to sqrt(1000000000) < 32000. Simple contiguous sieve of Eratosthenes is more than adequate for this. (Having sieved the core bool sieve[] array (a related C code is here), do make a separate array int core_primes[] containing the core primes, condensed from the sieve array, in an easy to use form, since you have more than one offset segment to sieve by them.)

Then, for each given separate segment, just sieve it using the prepared core primes. 100,000 is short enough, and without evens it's only 50,000 odds. You can use one pre-allocated array and adjust the addressing scheme for each new pair m,n. The i-th entry in the array will represent the number o + 2i where o is an odd start of a given segment.

See also:

A word about terminology: this is not a "segmented sieve". That refers to the sieving of successive segments, one after another, updating the core primes list as we go. Here the top limit is known in advance and its square root is very small.

The same core primes are used to sieve each separate offset segment, so this may be better described as an "offset" sieve of Eratosthenes. For each segment being sieved, only the core primes not greater than its top limit's square root need be used of course; but the core primes are not updated while each such offset segment is sieved (updating the core primes is the signature feature of the "segmented" sieve).

For such small numbers you can simply search for all primes between 1 and 1000000000.

Take 62.5 mByte of RAM to create a binary array (one bit for each odd number, because we already know that no even number (except of 2) is a prime).

Set all bits to 0 to indicate that they are primes, than use a Sieve of Eratosthenes to set bits to 1 of all number that are not primes.

Do the sieve once, store the resulting list of numbers.

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]);
}

}

Your upper bound is 10^9. The Sieve of Eratosthenes is O(N loglogN) which is too much for that bound.

Here are a few ideas:

Faster primality tests

The problem with a naive solution where you loop over the range [i, j] and check whether each number is prime is that it takes O(sqrt(N)) to test whether a number is prime which is too much if you deal with several cases.

However, you could try a smarter primality testing algorithm. Miller-Rabin is polynomial in the number of bits of N, and for N <= 10^9, you only need to check a = 2, 7 and 61.

Note that I haven't actually tried this, so I can't guarantee it would work.

Segmented sieve

As @KaustavRay mentioned, you could use a segmented sieve. The underlying idea is that if a number N is composite, then it has a prime divisor that is at most sqrt(N).

We use the Sieve of Eratosthenes algorithm to find the prime numbers below 32,000 (roughly sqrt(10^9)), and then for each number in the range [i, j] check whether there is any prime below 32,000 that divides it.

By the prime number theorem about one in log(N) numbers are prime which is small enough to squeeze in the time limit.

#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;}
标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!