1. 程式人生 > >篩法求素數POJ2262Goldbach’s Conjecture

篩法求素數POJ2262Goldbach’s Conjecture

/*
篩法求素數,首先從2開始將2的倍數全部篩掉,尋找下個未被篩掉的數字(就是下一個素數)
*/


#include<iostream>
#include<cmath>
#include<cstring>
using namespace std;
const int LEN=1000000+5;
const int Sqrt_Len=ceil(sqrt((double) LEN));
bool isPrimes[LEN];

void findPrimes(){
    memset(isPrimes,true,sizeof(isPrimes));//初始化素數表
    isPrimes[0
]=isPrimes[1]=false; for(int i=2;i<=Sqrt_Len;i++){//篩法求素數 if(isPrimes[i] == false)//尋找下一個素數 continue; int multiple=2;// while(true) { int multiNum = multiple * i; if(multiNum > LEN) break; isPrimes[multiNum]
= false; multiple++; } } } bool printGoldbach(int n){//打表 for(int i=3;i<n;i++){ if(!isPrimes[i]) continue; if(isPrimes[n-i]){ cout<<n<<" = "<<i<<" + "<<n-i<<"\n"; return true; } }
return false; } int main(){ findPrimes(); int n; while(cin>>n && n!=0){ if(!printGoldbach(n)) cout<<"Goldbach's conjecture is wrong.\n"; } return 0; }
題意分析:
     證明任意一個大於4的偶數n都可以寫成兩個奇素數(非2質數)之和, 其中n∈[6,1000000)且為偶數
     其實就是證明100萬以內的哥德巴赫猜想.
 
    解題思路:
     主要分兩步走:
     ① 求出100萬以內所有素數
     ② 在這個素數集中找出兩個奇素數,使其之和等於n(根據題意若存在多個組合則取差值最大的一組)
 
     第①步只需要打表做一次即可,
     第②步也不難:在素數表中找出比n小的最大一個素數x,
       若y=n-x也在素數表中, 且 x,y != 2,則x,y就是解;
       反之繼續找比x小的下一個素數,重複這個步驟即可.
 
     那麼問題在於第①步,如何快速找到100萬內的所有素數。
     關於素數的求解方法,不外乎用到:
      定義:只能被1或者自身整除的自然數(不包括1),稱為素數
      定理:如果一個數k是合數,那麼它的最小質因數肯定<=sqrt(k) 
            由於一個自然數若不是合數則必是素數,這個定理可以反過來用於素數:
            如果一個數k是素數, 那麼k必不能被<=sqrt(k)的所有整數整除
      演算法:埃拉託斯特尼篩法,也簡稱篩法,是一種空間換時間演算法.
            篩法主要用於求出某一個範圍內的所有素數,而不用於判斷某個數是否為素數.
            其主要思想是利用了合數定理, 剔除範圍內所有合數,剩下的必是素數.
            例如要求 (1, n] 以內的所有素數:
              那麼把2的所有倍數刪掉(不包括2);
              在剩下的數中第一個是3,把3的所有倍數刪掉(不包括3);
              在剩下的數中第一個是7,把7的所有倍數刪掉(不包括7)......
              一直重複直到遍歷完 (1, sqrt(n)] 範圍內的所有數,那麼剩下的就是這個範圍內的素數
 
 
      常規情況下,
        使用定義+定理求解素數,時間複雜度約為O(n*sqrt(n)),超過千萬級的話短時間內跑不動
        使用篩法求解素數,時間複雜度可達到O(n),但空間複雜度也達到了O(n) 

[ EXP 技術分享部落格 ] 版權所有, 轉載請註明出處: [ http://203.195.132.63/2018/06/14/pid-302/ ]