篩法求素數POJ2262Goldbach’s Conjecture
阿新 • • 發佈:2018-11-17
/* 篩法求素數,首先從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/ ]