哥德巴赫猜想

一 哥德巴赫猜想

哥德巴赫猜想可分为两种猜想,一种也称为“二重哥德巴赫猜想”,另一种就是“三重哥德巴赫猜想”。

具体为:1. 每个不小于6的偶数都可以表示为两个奇素数之和;

           2. 每个不小于9的奇数都可以表示为三个奇素数之和;

ps:1 不是素数。

笔试有题,让输出6~10 0000 之间的偶数都可以用两个奇素数之和表示出来,即 a = b + c,程序输出b,和c,若满足条件的有多个组合,输出一组即可。【注意时间效率】

看到这题,首先想到的就是求素数,而且需要注意时间效率。

空间置换时间,那就求出小于10 0000的素数保存至数组,然后同时从头和尾扫描这个数组,b指向数组头,c指向数组尾,

若b+c==a,break;

若b+c > a, --b;

若b+c <a , ++c;

不管这种思路对错,首要问题是求素数。素数的英文名是啥来着??忘记了,%>_<%  prime

二 求素数

编程求素数,一直都是梦魇,噩梦。因为,知道有很多种方法,但,书到用时方恨少。代码到写时,发现记住的太少(理解的太少)。简单回忆下集中求素数的方法。

1、简单朴素求素数方法

根据素数的定义,约数只有1和它本身的整数称为素数,假设一个整数为n,于是最简单的判断n是否是素数的方法就是从2到n-1都枚举一遍,判断是否存在能整数n的整数,如果都不能整除,ok,n为素数。

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

2、改进的求素数方法

第一种方法中,时间复杂度为O(n),因此必须进行改进。对于一个小于n的整数x,如果n能被x整除,因此n肯定能被n/x整除。

举例:如果n能够被2整除,写作 n  2  n/2

   如果n能够被3整除,写作 n 3 n/3 

        如果n能够被4整除,写作 n 4 n/4 

        ……

    如果n能够被sqrt(n)整除,写作 n sqrt(n) sqrt(n)

代码如下: 

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

通过分析可知,这个方法的时间复杂度为O(sqrt(n))

3. 筛选法

如果某个数m是另一个数n的倍数,则m肯定不是素数。所以我们可以在某个范围内,将已知素数的所有倍数都筛去,剩下的肯定都是素数,因为只有它不是其他数的倍数(1和它本身除外)。

具体做法是: 先把N个自然数按次序排列,1不是质数,也不是合数,要划去。

2是质数,保存。同时把后面的所有能被2整除的数都划去。

2后面第一个没划去的是3,把3留下,同时把3后面所有被3整除的数都划去。

3后面第一个没被划去的是5,把5留下,同时把5后面所有被5整除的数都划去。

这样一直做下去,就会把不超过N的全部合数筛掉,保留下来小于N的素数。

#define MAX 1000

bool isprime[MAX];
void ThePrimes()
{
  int i,j;
  for (i = 2; i < MAX; i++)
  {
      isprime[i]=1;
  }
  for (i = 2; i < MAX; i++)
  {
      if (isprime[i])
      {
          for (j = i+i; j < MAX; j+=i)
          {
              isprime[j] = 0;
          }
      }
  }
}

执行完本算法后,isprime[i]==1,则说明i是素数。所以在O(1)时间内,能够判断MAX以内的任意数是否为素数。而且,该算法的时间复杂度为O(loglogn).

4、改进的筛选法

可以为筛选法增加一个数组,记录已经找到的素数,通过这些已经找到的素数,来筛掉后面的数,由于每个数都可以分解成质因数的形式,所以所有质因数都被筛掉后,自然不在素数列表中了。

#define MAX 1000
bool isprime[MAX];
int p[MAX];
void prime(int n)
{
  memset(isprime,0,sizeof isprime);
  memset(p,0,sizeof p);
  int np=0;
  for (int i=2;i<=n;i++)
  {
      if(!isprime[i]) p[np++]=i;
      for (int j = 0;j<np&&p[j]*i<=n;j++)
      {
          isprime[p[j]*i] = 1;
          if(i%p[j]==0) break;
      }
  }

}

5、可以先求出sqrt(n),内的素数,然后进行筛选。此处不写代码了。

利用上述五种方法中的一种,计算出素数,然后扫描即可。

但是,10 0000 这个算是大数据了。用此种方法不妥。还不如分别找N/2,左右的素数,b 为小于N/2的最大素数,c为大于N/2的最小素数,比较a?=b+c,不等的话,就继续找合适的b和c的值。

int i = 1; i < N/2; i++

{

   if(isprime(N/2-i)&&isprime(N/2+i))

   { 输出即可}

}

 先到这儿吧

 

原文地址:https://www.cnblogs.com/slysky/p/2726267.html