數論 之 篩法總結(艾托拉斯特尼篩法+尤拉篩法)
阿新 • • 發佈:2018-12-14
1.篩法:
2.埃拉託斯特尼篩法(素數/質數篩選法):
2.1 步驟:
給出要篩數值的範圍n,找出以內的素數。先用2去篩,即把2留下,把2的倍數剔除掉;再用下一個素數,也就是3篩,把3留下,把3的倍數剔除掉;接下去用下一個素數5篩,把5留下,把5的倍數剔除掉;重複進行......
詳細列出演算法如下:
- 將2的倍數(用紅色標出),序列變成: 2 3 4 5 6 7 89 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
- 如果現在這個序列中最大數小於最後一個標出的素數的平方,那麼剩下的序列中所有的數都是素數,否則回到第二步。
- 本例中,因為25大於2的平方,我們再重新執行:
- 剩下的序列中第一個素數是3,將主序列中3的倍數劃出(紅色),主序列變成: 2 3 4 5 6 7 89 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
- 我們得到的素數有:2,3
- 25仍然大於3的平方,所以我們還要返回第二步:
- 現在序列中第一個素數是5,同樣將序列中5的倍數劃出,主序列成了: 2 3 4 5 6 7 89 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
- 我們得到的素數有:2 3 5 。
- 因為25等於5的平方,跳出迴圈.
去掉有顏色的數字,2到25之間的素數是:2 3 5 7 11 13 17 19 23。
2.2 程式碼模板:
#include<bits/stdc++.h> using namespace std; #define MAXN 100000000 int primes[MAXN],tot=0; bool isPrime[MAXN]; void getPrime(int n) { memset(isPrime,true,sizeof(isPrime));//一開始假設所有數都成立 for(int i=2;i<n;i++) { if(isPrime[i]) { primes[++tot]=i; for(int j=i+i;j<n;j+=i)//成倍數增加,對應詳細演算法介紹部分 isPrime[j]=false; } } for(int j=1;j<=tot;j++) { printf("%d\n",primes[j]); } } int main() { int n; cin>>n; getPrime(n); return 0; }
3.尤拉篩法:
3.1尤拉篩介紹: 尤拉篩又稱線性篩,可以線上性的時間內篩出素數,因此在時間上要優於埃拉託斯特尼篩法。
3.2程式碼:
#include<bits/stdc++.h>
using namespace std;
#define MAXN 100000000
int primes[MAXN],tot=0;
bool isPrime[MAXN];
void getPrime(int n)
{
memset(isPrime,true,sizeof(isPrime));
for(int i=2;i<n;i++)
{
if(isPrime[i])
primes[++tot]=i;
for(int j=1;j<=tot;j++)
{
if(i*primes[j]>=n)
break;
isPrime[i*primes[j]]=false;
if(i%primes[j]==0)
break;
}
}
for(int j=1;j<=tot;j++)
{
printf("%d\n",primes[j]);
}
}
int main()
{
int n;
cin>>n;
getPrime(n);
return 0;
}
3.2.1一行神奇的程式碼:
if(i%prime[j]==0)break;
這行程式碼神奇地保證了每個合數只會被它的最小素因子篩掉,就把複雜度降到了O(N)。
4.參考: