2023年更新版:
篩法求素數&線性篩法求素數
要理解篩法求素數首先要知道乙個定理,
整數唯一分解定理:任意大於等於2的正整數都有且只有一種方式寫出其質因子的乘積表示式。
a =p1p2p3p4…pn(pi是素數且pi
<=pj)
eg:2=2
4=22
12=223
36=2233
也就是說任意乙個合數都能分成乙個素數和另乙個數(另乙個數可以是素數也可以是合數)的乘積
eg:4=22
12=26
15=3*5
即任意乙個合數都有乙個比它本身小的素因子。
這樣的話,如果要求1-n的所有素數,只要把1-n內所有素數的倍數刪掉,剩下的就都是素數了。
先看**:
普通篩法求素數:
#include#include#includeusing namespace std;
#define ll long long
#define n 100
bool isprime[n];//1
int pri[n];//2
void prime()}}
return;
}
上邊**裡:
isprime陣列的作用是,判斷乙個數是否是素數,我們可以規定
if(isprime[i]==0)代表i是素數
else 代表i是合數
一開始把isprime陣列的值全部置0,假設1-n內所有數都是素數,然後把ispime[1]特判掉
2.pri陣列用來儲存已經確定的素數
3.乙個迴圈從2開始到sqrt(n)結束,迴圈內如果發現isprime[i]==0,那麼把i存到pri陣列內(即上面的4那一行),接著再來乙個迴圈把i這個素數的倍數全部刪掉(上面的5),這個迴圈從i*i開始,每次加i,到n結束,這樣就可以把i*i,i*(i+1),i*(i+2)…i*(i+k),把n以內i的倍數全部刪掉。
接著說1 .為什麼到sqrt(n)就可以結束了:
假設乙個小於n的合數 x=ab ,設 a<=b;
那麼a必定小於sqrt(n),也就是說這個合數必定有乙個小於 sqrt(n)的素因子,那麼這個數一定能在2-sqrt(n)內被某個數刪掉
2.為什麼從i *i開始而不是從2*i開始
假設乙個合數x=ij (j < i )
那麼這個數在遍歷 j 時就已經被刪掉了
然後看線性篩法
仔細分析上面的篩法其實是會造成重複篩合數,比如 12 在遍歷2的時候篩到2*6 篩掉一次,在遍歷3的時候篩到3*4 又篩了一次
快速篩法就解決了這個問題
先看**:
#include#include#includeusing namespace std;
#define ll long long
#define n 100
bool isprime[n];
int pri[n];
void prime2()
for(int j=1;j上邊**:
1。不管i是素數還是合數,都會執行到「1「這個地方。
這個迴圈的作用是
如果i是素數,會篩掉所有的i*k(其中k是所有小於等於i的素數)
看**j從1開始,到cnt-1結束,每次把i*pri[j]標記為合數,即是說把從pri[1]=2到pri[cnt-1],與i的乘積篩掉
eg:i=5 時,j從1開始,此時cnt等於3 ,即j到3結束,會把5*2,5*3,篩掉
如果i是合數,會篩掉所有的i*k(其中k是所有小於等於i的最小素因子的素數)
看**j從1開始,到cnt-1結束,每次把i*pri[j]標記為合數,然後「//2「這一行的作用就是在pri[j]等於i的最小素因子時跳出迴圈。因為pri[j]是從小到大列舉的,所以遇見的第乙個i%pri[j]==0就是i的最小素因子
現在證明這個篩法
不會造成重複篩
對於任意乙個 x =p1p2p3p4…pn(pi是素數且pi
<=pj)
這個x能且只能被y=p2p3p4…pn(pi是素數且pi
<=pj)篩掉。
eg:42=2*3*7,42只能被3*7=21篩掉。
可以把所有合數都篩掉
對於任意乙個 x =p1p2p3p4…pn(pi是素數且pi
<=pj)
這個數一定能被y=p2p3p4…pn(pi是素數且pi
<=pj)篩掉。
所以一定可以把所有合數都篩掉
線性篩法求素數
線性篩法求素數,顧名思義,其時間複雜度為o n 我是第一次接觸線性篩法求素數,其中有些難理解的地方的確花了很多時間。先放出 難點在於 為什麼這裡要break?先可以得出乙個結論,此時的prime j 為 i prime j 的最小質因數。現設x p1 a為合數,且p1為其最小的質因子,a為質數或合數...
素數篩法求素數
素數篩類似於打表標記,預先處理掉非素數的數,即素數的倍數 任意非素數都可以由幾個素數相乘得到 於是效率比暴力求解快得多。埃氏篩法的效率為o n loglog n 簡單易懂,但是會重複標記,比如當i為2時,6會被標記掉,然而當i為3時,6又會被重複標記,這樣的重複訪問加大了時間複雜度,於是有了尤拉篩。...
篩法求素數
素數篩法就是每次把已知的素數的倍數曬去,篩掉前sqrt n 中素數的倍數就可以了 先把n個自然數按次序排列起來。1不是質數,也不是合數,要划去。第二個數2是質數留下來,而把2後面所有能被2整除的數都劃去。2後面第乙個沒劃去的數是3,把3留下,再把3後面所有能被3整除的數都劃去。3後面第乙個沒劃去的數...