1. 程式人生 > 其它 >線性篩法求素數

線性篩法求素數

 

題目

給定一個正整數 n,請你求出 1∼n 中質數的個數。

輸入格式

共一行,包含整數 n

輸出格式

共一行,包含一個整數,表示 1n中質數的個數。

資料範圍

1n1e6

輸入樣例:

8

輸出樣例:

4
 

 

埃氏篩法

時間複雜度:O(nloglogn)

思路:

 (1)先把1刪除(現今數學界1既不是質數也不是合數)

(2)讀取佇列中當前最小的數2,然後把2的倍數刪去

(3)讀取佇列中當前最小的數3,然後把3的倍數刪去

(4)讀取佇列中當前最小的數5,然後把5的倍數刪去

(5)讀取佇列中當前最小的數7,然後把7的倍數刪去

(6)如上所述直到需求的範圍內所有的數均刪除或讀取

程式碼:

 1 #include<iostream>
 2 using namespace std;
 3 const int N=1e6+10;
 4 int prime[N],cnt;
 5 bool st[N];
 6 void get_prime(int n)
 7 {
 8     for(int i=2;i<=n;i++)
 9     {
10         if(!st[i])
11         {
12             prime[cnt++]=i;
13             for(int j=i+i;j<=n;j+=i) st[j]=true
; 14 } 15 16 } 17 } 18 int main() 19 { 20 int n; 21 cin>>n; 22 get_prime(n); 23 cout<<cnt<<endl; 24 return 0; 25 }

線性篩法

時間複雜度:O(n)

思路:

埃氏篩法中有些數是篩了多次的,有沒有什麼辦法使他只篩一次呢?(比如:12,在2的倍數時篩了一次,在3的倍數裡面也篩了一次)為此我們提出了線性篩法。

 

prime[]陣列中的素數是遞增的,當i能整除prime[j],那麼i*prime[j+1]這個合數

肯定被prime[j]乘以某個數篩掉。
因為i中含有prime[j],prime[j]比prime[j+1]小,即i=k*prime[j],那麼i*prime[j+1]=(k*prime[j])*prime[j+1]=K*prime[j],
接下去的素數同理。所以不用篩下去了。
因此,在滿足i%prime[j]==0這個條件之前以及第一次滿足改條件時,
prime[j]必定是prime[j]*i的最小因子。

程式碼:

 1 #include<iostream>
 2 using namespace std;
 3 const int N=1e6+10;
 4 int prime[N],cnt;
 5 bool st[N];
 6 void get_prime(int n)
 7 {
 8     for(int i=2;i<=n;i++)
 9     {
10         if(!st[i]) prime[cnt++]=i;
11         for(int j=0;prime[j]<=n/i;j++)
12         {
13             st[prime[j]*i]=true;
14             if(i%prime[j]==0) break;
15         }
16     }
17 }
18 int main()
19 {
20     int n;
21     cin>>n;
22     get_prime(n);
23     cout<<cnt<<endl;
24     return 0;
25 }