查找特定序列的所有素数

时间:2013-04-29 07:00:10

标签: c

我正在尝试在C中编写一个程序,找到连续5位数素数(a,b,c,d,e,f)的所有序列,其方式是b = a + 2,c = b + 4,d = c + 6,e = d + 8,f = e + 10.

我的解决方案如下:

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


bool IsPrime(int x){

    for (int i = 2; i < x; i++){
        if (x % i == 0 && x != i) return false;
    }
    return true;
}           


int main(void){

    int a,b,c,d,e,f;


    for (int i = 10000; i < 99999; i++){
        if (IsPrime(i) == true && IsPrime(i + 2) == true && IsPrime(i + 6) == true && IsPrime(i + 12) == true && IsPrime(i + 20) == true && IsPrime(i + 30)){
            a = i;
            b = i + 2;
            c = i + 6;
            d = i + 12;
            e = i + 20;
            f = i + 30;
            printf("%i %i %i %i %i %i \n", a, b, c, d, e, f);
            a, b, c, d, e, f = 0;
        }
    }



// end
} 

给出以下输出:

  

13901 13903 13907 13913 13921 13931

     

21557 21559 21563 21569 21577 21587

     

26681 26683 26687 26693 26701 26711

     

28277 28279 28283 28289 28297 28307

     

31247 31249 31253 31259 31267 31277

     

33617 33619 33623 33629 33637 33647

     

55661 55663 55667 55673 55681 55691

     

68897 68899 68903 68909 68917 68927

     

97367 97369 97373 97379 97387 97397

然而,正确的解决方案是显而易见的:

13901   13903   13907   13913   13921   13931

21557   21559   21563   21569   21577   21587

28277   28279   28283   28289   28297   28307

55661   55663   55667   55673   55681   55691

68897   68899   68903   68909   68917   68927

如您所见,我的解决方案(上面的第一个输出集)包含正确解决方案中的所有主要序列(上面的第二个输出集),以及一些其他解决方案。我被告知我的解决方案在a,b,c,d,e和f之间有多余的素数,这就是为什么正确的解决方案包含较少的解决方案。有人可以解释为什么我的输出中的某些行是多余的(它们似乎符合问题的主要条件)?另外,如何从我的解决方案中消除冗余集?

3 个答案:

答案 0 :(得分:7)

对于任何i,您正在检查以下内容的素数:

i
i + 2
i + 6
i + 12
i + 20
i + 30

如果所有这些都是素数,它仍然不满足谓词,除非你还确定这些是连续的素数。因此,您需要检查数字i + 4i + 8等(通过i + 28不是素数。 (您无需检查i + an_odd_number,因为如果ii + 2都是素数,则永远不会成为素数。)

答案 1 :(得分:0)

//Fixed

bool IsPrime(int x){
    //some changes to make the code run faster.
    if (x < 2) return false;
    for (int i = 2; i*i < x; ++i)
    {
        if (x % i == 0) return false;
    }
    return true;
}           


int main(void){

    int a,b,c,d,e,f;


    for (int i = 10001; i < 99999; i+=2){
        //continue for all the wrong cases.
        if (!IsPrime(i)) continue;
        if (!IsPrime(i+2)) continue;
        if (!IsPrime(i+6)) continue;
        if (!IsPrime(i+12)) continue;
        if (!IsPrime(i+20)) continue;
        if (!IsPrime(i+30)) continue;

        //Those checks if you need to validate no primes in the middle.
        if (IsPrime(i+4)) continue;
        if (IsPrime(i+8)) continue;
        if (IsPrime(i+10)) continue;
        if (IsPrime(i+14)) continue;
        if (IsPrime(i+16)) continue;
        if (IsPrime(i+18)) continue;
        if (IsPrime(i+22)) continue;
        if (IsPrime(i+24)) continue;
        if (IsPrime(i+26)) continue;
        if (IsPrime(i+28)) continue;

        //If we got here, all is good.
        a = i;
        b = i + 2;
        c = i + 6;
        d = i + 12;
        e = i + 20;
        f = i + 30;
        printf("%i %i %i %i %i %i \n", a, b, c, d, e, f);
    }

// end
} 

更快的方法是以数组(或任何其他方式)保存您检查“最佳状态”的最后15个奇数,然后仅检查序列是否正确。因为在当前的方法中,您可以检查一个数字是否为最多15次。

答案 2 :(得分:0)

你没有注意素数是连续的要求,而你的代码要慢得多。保留最后6个素数的队列,在队列末尾插入每个素数并删除第一个素数......这可以通过圆形数组轻松完成。每次插入素数时,检查差异条件是否适用...如果是这样,你有一个解决方案。

对于你的IsPrime例程,你只需要检查x的平方根,你不需要检查i!= x,因为它总是更少。

这是一个有效的解决方案:

#include <stdio.h>
#include <stdbool.h>

static inline int next(int i)
{
    return (i + 1) % 6;
}

static void check(int* p, int x)
{
    for (int i = 0; i < 5; i++, x = next(x))
        if (p[next(x)] - p[x] != (i+1) * 2)
            return;

    for (int i = 0; i < 6; i++)
        printf("%d%c", p[x = next(x)], i == 5? '\n' : ' ');
}

static bool isPrime(int n)
{
    for (int i = 3; i*i < n; i += 2)
        if ((n % i) == 0)
            return false;
    return true;
}

int main(int argc, char** argv)
{
    int cp[6] = { 0 };
    int x = 0;

    for (int i = 10001; i <= 99999; i += 2)
        if (isPrime(i))
        {
            cp[x] = i;
            check(cp, x = next(x));
        }

    return 0;
}

更快的解决方案是使用预先计算的素数表...使用

static int primes[316]; // sqrt(99999)
static int nprimes;

static bool isPrime(int n)
{
    for (int i = 0; i < nprimes; i++)
        if ((n % primes[i]) == 0)
            return false;
    return true;
}

并添加

for (int n = 3; nprimes < 316; n += 2)
    if (isPrime(n))
        primes[nprimes++] = n;

在主循环之前。

对于一般解决方案,使用非常大的素数,您可以使用Segmented Sieve of Erastothenes生成前N个素数。