利用筛选法(埃筛法)解决素数个数问题
例题: n以内素数个数
输入格式:
请给出最大整数以内的一个数字n。
输出格式:
输出n以内素数的个数。
输入样例:
在这里给出一组输入。例如:
1000
输出样例:
在这里给出相应的输出。例如:
168
代码长度限制
16 KB
时间限制
10000 ms
内存限制
128 MB
当我们处理“N是否为素数”问题时我们通常会考虑使用循环求余来判断:
- 首先我们会定义i从2到sqrt(n)的循环
- 然后不断增加i,用if(N%i==0)来进行判断
#include<cstdio>
#include<cmath>
#include<algorithm>
#include <iostream>
#include <algorithm>
#include<iostream>
bool IsSu(int x)//判断素数
{
int i;
int k = (int)sqrt((double)x);
for (i = 2; i <= k; i++)
{
if (x % i == 0)
{
return false;
}
}
return true;
}
int main()
{
int n;
int count=0;
scanf("%d", &n);
for (int i = 2; i <= n; i++)
{
if (IsSu(i))//判断素数,是则加一
{
count++;
}
}
printf("%d",count);
}
但此种方法的n空间复杂度较大,遇到n足够大时就会产生超时。
于是,可以考虑筛除法(埃筛法):
- 首先设置一个素数数组下标对应数字,其内容1或0代表此数为是或不是素数
- 先假设全是素数,再从i=2开始,如果为素数,则进入下层循环(将2的倍数改为非素数,一直到i=N结束),
- 上层循环则也需遍历一遍2到N
#include<cstdio>
#include<cmath>
#include<algorithm>
#include <iostream>
#include <algorithm>
#include<iostream>
using namespace std;
const int MAX = 1e9 + 10;//设置最大值
char su[MAX + 10];//用char类型节省内存,1则为是素数,0则不是。
int n;
int main()
{
scanf("%d", &n);
int count = 0;//记录素数个数
for (int i = 2; i <= n; i++)//先将所有元素都认为是素数
{
su[i] = 1;
}
for (int i = 2; i <= n; i++)//利用埃筛法制作素数数组
{
if (su[i] == 1)//如果是素数则进入循环,将他的倍数设为0
{
for (int j = i * 2; j <= n; j += i)//循环找到他的倍数
{
su[j] = 0; //将其标记为非素数
}
}
}
for (int i = 2; i <= n; i++)//判断N以内的素数
if (su[i])//如果是素数则个数加一
count++;
printf("%d", count);
return 0;
}
关于的埃筛法内容推理:
素数是仅能被它本身和1整除的任何整数。埃拉托斯特尼筛法,简称埃氏筛,是一种由希腊数学家埃拉托斯特尼所提出的一种简单检定素数的算法。要得到自然数n以内的全部素数,必须把不大于根号n的所有素数的倍数剔除,剩下的就是素数。算法思想:给出要筛数值的范围,找出其以内的素数。先用2去筛,即把2留下,把2的倍数剔除掉;再用下一个质数3去筛,把3留下,把3的倍数剔除掉;接下去用下一个质数5筛,把5留下,把5的倍数剔除掉;不断重复下去......
如图所示: