**一般而言,当数据较小时,我们求1到n的素数,可以使用双重循环暴力求解,充其次也就用个sqrt(n)优化一下,如:
#include<iostream>
#include<cmath>
using namespace std;
int main()
{
int n,i,j,b;
cin>>n;
for(i=2;i<=n;++i){
b=0;
for(j=2;j<=sqrt(i);++j){
if(i%j==0){b=1;break;}
}
if(b==0)cout<<i<<endl;
}
return 0;
}
不过在算法题中,往往不会有这么简单的让我们来求解,出题人经常会把数据出的很大,这个时候,身为当代好青年的我们就学要学习新东西了,比如埃氏筛**
埃拉托斯特尼筛法,简称埃氏筛或爱氏筛,是一种由希腊数学家埃拉托斯特尼所提出的一种简单检定素数的算法。要得到自然数n以内的全部素数,必须把不大于根号n的所有素数的倍数剔除,剩下的就是素数。
讲完原理,就直接上代码吧(狗头保命)
洛谷上的P3912题
题目描述
求 1,2,⋯,N 中素数的个数。
输入格式
一行一个整数 N。
输出格式
一行一个整数,表示素数的个数。
说明/提示
1<N<10^8
数据比较大,所以呢,一般的埃氏筛,自然也是拿不到满分啦,再次狗头保命
#include<iostream>
using namespace std;
bool isprime[100000005];
int main()
{
int n,i,cnt;
cin>>n;
for(int i=0;i<100000005;++i)isprime[i]=true;//这里赋值为真,后面可以优化
isprime[0]=false;isprime[1]=false;//这里,可有可无
for(int i=2;i<=n;++i){
if(isprime[i]){
for(int j=i*2;j<=n;j+=i){//这里筛掉前面素数的倍数
isprime[j]=false;
}
}
if(isprime[i])++cnt;//计数即可
}
cout<<cnt;
return 0;
}
这是包装成函数的情况
#include<iostream>
using namespace std;
bool isprime[100000005];
void is(int n)
{
for(int i=0;i<100000005;++i)isprime[i]=true;
isprime[0]=false;isprime[1]=false;
for(int i=2;i<=n;++i){
if(isprime[i]){
for(int j=i*2;j<=n;j+=i){
isprime[j]=false;
}
}
}
}
int main()
{
int n,i,cnt;
cin>>n;
is(n);
for(i=1;i<=n;++i){
if(isprime[i])++cnt;
}
cout<<cnt;
return 0;
}
下面,我们对其进行优化!!!
先看完整代码:
#include<iostream>
using namespace std;
bool a[100000005];
int main()
{
int n,i,cnt=0;
cin>>n;
for(int i=2;i*i<=n;++i){//其他博客写的是for(i=0;i<n;++i),这里可以改成这样,因为在前面已经筛过了
if(a[i]==0){
for(int j=i*i;j<=n;j+=i){//这里直接j=i*i,而不用j=i*2;因为前面有2*i,3*i,4*i....,(i-1)*i
a[j]=1;
}
}
}
for(i=2;i<=n;++i){
if(a[i]==0)++cnt;
}
cout<<cnt;
return 0;
}
接下来我们再来分析
首先我们看
for(int i=0;i<100000005;++i)isprime[i]=true;
这里我们对其进行赋值,但是既然我们把他定义在主函数外面,那么是不是他的初值为0,而bool类型只有0和1两个值,这正好可以和true,false对应只不过需要把0当作真而已
而这里核心代码
for(int i=2;i*i<=n;++i){//其他博客写的是for(i=0;i<n;++i),这里可以改成这样,因为在前面已经筛过了
if(a[i]==0){
for(int j=i*i;j<=n;j+=i){//这里直接j=i*i,而不用j=i*2;因为前面有2*i,3*i,4*i....,(i-1)*i
a[j]=1;
}
}
}
优化了两个地方,一层循环和二层循环,一层循环处,i只累加到了ii<=n处,这是因为在前面的i已经将后面的数筛掉了
另一处j不等于i2,而是j=ii,因为前面有2i,3i…,i(i-1),都筛过了,因此在此处也就不需要在重复了。
因为没有循环一部分i,因此就将这部分计数单独列出来:
for(i=2;i<=n;++i){
if(a[i]==0)++cnt;
}
到这里优化也就结束了,不过要想变得更强,吾辈仍需继续学习啊,因此,欧拉筛法不失为你的一种选择哦,加油少年!!!
共勉之!!!