问题:输入正整数N,求1~N范围内素数的个数,2≤N≤1,000,000
样例输入:
10000
样例输出:
1229
1.定义法
#include <bits/stdc++.h>
using namespace std;
int isprime(int n){
for(int i =2;i<=n/i;i++){
if(n%i==0){
return 0;
}
}
return 1;
}
int main(){
long long n;
cin>>n;
int cnt =0;
for(long long i =2;i<=n;i+=2){
if(isprime(i)){
cnt++;
}
}
cout<<cnt;
}
2.朴素筛法
#include <bits/stdc++.h>
using namespace std;
//bitset<N> bitset1; // 创建一个长度为 N 的 bitset,所有位都被初始化为 0
const int maxn = 1e6+10; //常数的定义
bitset <maxn> pri; //1:合数 0:素数
int isprime(int n){
for(int i =2;i<=n/i;i++){
if(n%i==0){ //合数
return 0;
}
}
return 1; //素数
}
int main(){
long long n;
cin>>n;
int cnt = 0;
for(int i =2;i<=sqrt(n);i++){
if(isprime(i)){ //i是素数,对i的倍数进行合数判定
for(int j = 2*i;j<=n;j+=i)
pri[j] = 1;
}
}
for(int i =2;i<=n;i++){
if(!pri[i]){
cnt++;
}
}
cout<<cnt<<endl;
}
3.埃氏筛法(在朴素筛法基础上进行)
#include <bits/stdc++.h>
using namespace std;
//bitset<N> bitset1; // 创建一个长度为 N 的 bitset,所有位都被初始化为 0
const int maxn = 1e6+10; //常数的定义
bitset <maxn> pri; //1:合数 0:素数
int main(){
long long n;
cin>>n;
int cnt = 0;
for(int i =2;i<=sqrt(n);i++){
if(!pri[i]){ //更快且不需要进行素数判断因为2为最小素数从小到i若i没有被筛掉则说明i是素数
for(int j =i*i;j<=n;j+=i)
//因为2*i 当i等于2时已经有过2*3等等则当i等于3时则不需要再次进行2*i直接从i*i开始即可
pri[j] = 1;
}
}
for(int i =2;i<=n;i++){
if(!pri[i]){
cnt++;
}
}
cout<<cnt<<endl;
}
4.欧拉筛法(最快)
埃氏筛选的弊端
举例说明:
120 在埃氏筛选中存在多次被筛
120 = 2*2*2*3*5
当i=2时被筛一次,当i=3时被筛一次,当i=5,6,8等等又会被筛一次,重复多次的被筛选,而欧拉筛选则是解决上述弊端的
具体见代码:
#include <bits/stdc++.h>
using namespace std;
const int maxn =1e6+10;
bitset<maxn> pri; //0:素数 1:合数
int primes[maxn],pp=0;
int main(){
int n,cnt =0;
cin>>n;
for(int i =2;i<=n;++i){
if(!pri[i]){ //i:素数
primes[++pp] = i;
cnt++;
}
for(int j = 1;primes[j]*i <= n;++j){
pri[primes[j] * i] = 1;
if(i%primes[j] == 0) break; //优化重点,用于限制i每次筛选的最大值
}
}
cout<<cnt<<endl;
return 0;
}
总结:
几种方法之间关联性比较强,步步优化,建议从头看起,不要一步见底!