文章是看了好多好多大佬的部落格才自己總結出來的,有些地方覺得大佬的文字很精煉於是學習了一下,若是有人認為哪些地方我是不道德的,請指出,謝謝。
質數,也稱素數,只包含兩個因數,且乙個因數為1,乙個因數為它本身。
無論是數論、計算機應用上還是acm上,質數都是基礎且極其重要。於acm上,質數經常用於判斷乙個數是否是質數或是列舉乙個區間的質數。
現於acm的需求初步學習質數,列舉1~n內的質數。
一、究極暴力法
從1列舉到n,計算能整除n的數的個數。複雜度o(n^2)。
二、暴力法優化
比2大的所有偶數一定不是質數。並且列舉可以只列舉到sqrt(n)即可,證明如下:
n = sqrt(n) * sqrt(n)
設 n = x * y,且 x >= sqrt(n),則必有 y <= sqrt(n)
那麼意味著當我從小到大列舉的時候,若是找到了 y 便不需要找 x 了
故列舉到 sqrt(n) 足夠了
證畢
#include#includeusing namespace std;
const int maxp = 700000;
int prime[maxp];
int main()
if(j * j > i) prime[sub++] = i;
}return 0;
}
複雜度o(n * sqrt(n))。若資料量不大的話可以用這種方法。
三、暴力法再優化
其實只列舉 3 到 sqrt(n) 的所有奇數也會出現重複判斷的情況。
例如:列舉 3 到 sqrt(101) 的所有奇數為:3, 5, 7, 9,此處就會發現既然都不會整除 3 那麼一定不會整除 9 !
故不僅僅是奇數,3 到 sqrt(n) 中之前記錄的質數的整數倍也可以跳過。此時我們再討論一下 3 到 sqrt(n) 之間有些什麼數:偶數,奇數中質數的整數倍,質數,奇數中既不是質數又不是質數的整數倍的數。其實分析可得奇數中既不是質數又不是質數的整數倍的數是不存在的,證明如下:
設 y 是乙個奇數,且 y 不是質數,且不是質數的整數倍
由 y 不是乙個質數,假設 y = p1 * p2 * ... * pn
由 y 是奇數可知 pi ( 1 <= i <= n)必不為偶數,又 pi 也不為質數, 則 pi 也是和 y 乙個定義,pi是乙個奇數中既不是質數又不是質數的整數倍的數
再像處理 y 一樣的處理 pi ,又可以得到乙個 pi 的因子pii,同時 pii 也是乙個奇數中既不是質數又不是質數的整數倍的數。。。無限迴圈下去
所以,這樣的奇數中既不是質數又不是質數的整數倍的數是不存在的
證畢那麼會發現 3 到 sqrt(n) 我們只要嘗試小於 sqrt(n) 的所有質數就可以了。
#include#includeusing namespace std;
const int maxp = 700000;
int prime[maxp];
int main()
if(j >= sub) prime[sub++] = i;
}return 0;
}
複雜度再降,o(n * n之前的質數個數)。
四、篩法
篩法,顧名思義,不停的將合數篩出去,剩下的就只有質數。
先簡單的說一下篩法的步驟:(篩 1 ~ n 的質數)
首先最小質數是 2,那麼 1 ~ n 中所有的 2 的倍數全部去掉。剩下的數中最小的是 3 ,那麼 3 是質數。再把 3 的倍數 都給去掉,剩下所有的數中最小的是 5,再去 5 的倍數。。。不斷迴圈此過程,最後就可以把1 ~ n 之間的所有質數全部篩出來了。
證明不再給出,性質同上面證明(三、暴力再優化)。若還是不理解,請仔細分析質數的性質 「任一大於1的自然數,要麼本身是質數,要麼可以分解為幾個質數之積,且這種分解是唯一的」。
#include#include#includeusing namespace std;
const int maxn = 1000000;
const int maxp = 700000;
bool vis[maxn]; //篩數陣列,0代表是質數,1代表不是質數
int prime[maxp]; //質數陣列
int main()
}return 0;
}
效率大大優化,複雜度在o(n)與o(n * n之前的質數個數)之間。
五、篩法優化
通過模擬一次上面篩法,不難發現會出現許多重複的地方。
對應篩法的**我們進行優化。j = i * i 優於 i * 2,舉例說明,當 i = 2 時,我們已經把 vis[10] 賦值為 1 了,當 i = 5 時,vis[10]會再賦值一次。所以 j = i * i 會減少一部分重複。 再者 i 只到 sqrt(n) 便足夠了,乙個數 x 大於 sqrt(n),那麼 x * x 一定大於 n,第二個迴圈都進不去,多餘的判斷。
給出優化後的**:
/*
此處**為白書《演算法競賽入門經典》的標準**
*/#include#include#includeusing namespace std;
const int maxn = 1000000;
const int maxp = 700000;
bool vis[maxn];
int prime[maxp];
int main()
}for(int j = sqrt(n) + 1; j <= n; j++)
if(!vis[j]) prime[sub++] = j;
return 0;
}
複雜度較暴力優化太多,別人還有很多更優化的演算法。但我覺得既然是白書上的**,已經很優秀,貪多嚼不爛,對於篩法的學習便到這了。
如果大佬發現了我的錯誤,也請你指出,謝謝!
數論問題之質數
若乙個正整數無法被1和它自身之外的任何自然數整除,則稱該數為質數 素數 否則該數為合數。質數的判定用試除法 bool is prime int n return true 質數的篩選方法 埃式篩法和線性篩法 鏈結 之前寫過,就不寫了 算術基本定理 任何乙個不大於1的正整數都能唯一分解為有限個質數的乘...
數論 質數距離
給定兩個整數l和u,你需要在閉區間 l,u 內找到距離最接近的兩個相鄰質數c1和c2 即c2 c1是最小的 如果存在相同距離的其他相鄰質數對,則輸出第一對。同時,你還需要找到距離最遠的兩個相鄰質數d1和d2 即d1 d2是最大的 如果存在相同距離的其他相鄰質數對,則輸出第一對。輸入格式 每行輸入兩個...
簡單數論 質數
在 1 的整數中,如果只包含1和本身兩個約數,這個數就被稱為質數 素數。質數的判定 試除法 暴力列舉 o n bool is prime int n 簡單優化 o sqrt 對任意的d能整除n d n 顯然n除上d也能整除n frac n 如n 12,3是12的約數,4也是12的約數 2是12的約數...