【數論】埃氏篩法


  這學期的離散數學課程學了一點初等數論,其中的埃氏篩法當時課上沒有太懂,課后看了《挑戰程序設計競賽》一書終於弄懂了。(這本書確實很好!算法簡潔優美。)

  如果只對一個整數進行素性測試,通常O(√n )的算法就足夠了。但如果要對許多整數進行素性測試,則有更為高效的算法,其中就包括埃拉托斯特尼篩法,簡稱埃氏篩法。它是一個與輾轉相除法一樣古老的算法,可以用於枚舉n以內的素數。

  首先,我們將2到n范圍內的所有整數寫下來。其中最小的數字2是素數。將表中所有2的倍數都划去。表中剩余的最小數字是3,它不能被更小的數整除,所以是素數。再將表中所有3的倍數都划去。依此類推,如果表中剩余的最小數字是m時,m就是素數。然后將表中所有m的倍數都化去。像這樣反復操作,就能依次枚舉n以內的素數。

 

 

如圖所示,最終我們就能得到20以內的所有素數。埃氏篩法的復雜度僅有O(nlognlogn)。對於程序設計競賽中的數據規模,將它的復雜度看作大致線性的也無妨。下面給出代碼: 

 1 #include <iostream>
 2 #include <cstring>
 3 using namespace std;
 4 
 5 //埃氏篩法
 6 
 7 const int MAX_N = 10005;
 8 int prime[MAX_N];  //第i個素數
 9 bool is_prime[MAX_N+1];  //is_prime[i]為true時表示i是素數
10 
11 //返回n以內素數的個數
12 int sieve(int n){
13     int p = 0;
14     for(int i = 0; i <= n; i++) is_prime[i] = true;
15     is_prime[0] = is_prime[1] = false;
16     for(int i = 2; i <= n; i++){
17         if(is_prime[i]){
18             prime[p++] = i;
19             for(int j = 2*i; j <= n; j+=i) is_prime[j] = false;  //篩去所有素數的倍數
20         }
21     }
22     return p;
23 }
24 
25 
26 int main()
27 {
28     int n;  //枚舉n以內素數
29     while(cin>>n){
30        int p = sieve(n);
31         cout<<p<<endl;
32         for(int i = 0; i < p;i++)
33             cout<< prime[i]<<" ";
34         cout<<endl;
35     }
36 
37     return 0;
38 }

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM