篩素數的三種方法
阿新 • • 發佈:2020-07-17
前言:
一道數學題,最難想的小奧部分做對了,最後敗在了篩素數(用了最質樸的方法
Q:求n以內的素數
A:
1.樸素
-
思路:判斷每一個數是否質數
-
時間複雜度:O(nsqrt(n))
-
程式碼:
#include <bits/stdc++.h> using namespace std; int n,cnt,keep[10005]; bool judge(int x) { if(x==1) return 0; if(x==2) return 1; for(int j=2;j*j<=x;++j){if(x%j==0) return 0;} return 1; } int main() { scanf("%d",&n); for(int i=1;i<=n;++i) if(judge(i)) keep[++cnt]=i; printf("%d\n",cnt); for(int i=1;i<=cnt;++i) printf("%d ",keep[i]); return 0; }
2.埃氏篩法
-
思路:每篩出一個質數,就標記n以內此素數的倍數不能選
-
時間複雜度:O(nloglogn)
-
程式碼:
#include <bits/stdc++.h> using namespace std; int n,cnt,keep[100005],temp[100005]; void sieve(int x) { temp[0]=temp[1]=1; for(int i=2;i<=x;++i) if(!temp[i]) { keep[++cnt]=i; for(int j=i+i;j<=x;j+=i) temp[j]=1; } } int main() { scanf("%d",&n); sieve(n); printf("%d\n",cnt); for(int i=1;i<=cnt;++i) printf("%d ",keep[i]); return 0; }
3.尤拉篩法
-
思路:和2.埃氏篩法略有相似;任何合數都能表示成多個素數的積,列舉最小質因子之積從而標記不可選的數
-
時間複雜度:尤拉篩法 o(n)
-
程式碼:
#include <bits/stdc++.h> using namespace std; int n,cnt,keep[100005],vis[100005]; void sieve(int x) { for(int i=2;i<=x;++i) { if(!vis[i]) keep[++cnt]=i; for(int j=1;j<=cnt,i*keep[j]<=x;++j) { vis[i*keep[j]]=1;//不能與下一句調換位置 if(i%keep[j]==0) break;//當i是keep[j]的整數倍時(i%keep[j] == 0),i*keep[j+1]肯定被篩過,跳出迴圈 } } } int main() { scanf("%d",&n); sieve(n); printf("%d\n",cnt); for(int i=1;i<=cnt;++i) printf("%d ",keep[i]); return 0; }
後記:
- 篩素數是一項必備工具
- 樸素做法是必須寫會的
- 後兩種思想相似,思維方向不同
- 感性理解尤拉篩法