Eratosthenes 筛法和线性筛法
Eratosthenes 筛法
很早就听他们提到过素数筛法的概念但是一直没有去查,直到一个月前写到一个关于素数的背包问题才发现不会筛法只能面对T的惨痛现实。今天早晨发现自己又双叒叕忘记怎么敲了……………。
Eratosthenes 筛法原理
基本原理:其实就是从2开始不断的筛去素数的倍数,这是由于每一个合数都能写为几个素数的幂的乘积。然后呢,如果比某个数小的所有素数都不能筛掉这个数的话这个数其实就是一个素数。基本原理很简单现在来看看具体如何实现。
实现步骤
1.两个数组,is_prime用来标记素数便于后续的筛法prime用来记录素数
2.通过memset现将所有的数标记为素数,之后再取消标记。
3.进入for循环从2开始筛,如果某一数没有被比它小的数筛去则下一次筛去它的倍数。
4.其中又一个小优化,筛素数的时候是从i*i开始筛的,因为如果i乘j(j<i),那么这个数会被j提前筛去。
代码
#define N 10005
bool is_prime[N];//记录是否是素数
int prime[N];//储存素数
int ans=0;//记录素数个数
int PRIME()
{
memset(is_prime, true,sizeof(is_prime));//现将所有的是认为是素数便于之后筛选
is_prime[0]=0;//取消0,1的标记
is_prime[1]=0;
for(int i=2;i<=N;i++)//从2开始取消2的倍数的标记
{
if(is_prime[i])//如果是素数则可以筛掉他的倍数
{
prime[ans++]=i;
for(int j=i*i;j<=N;j=j+i)//可以跳过i-i*i中的数,因为它会被小于i的数筛掉
{
is_prime[j]=false;
}
}
}
return 0;
}
线性筛
原理
直接上盗的图
线性筛比起前面的埃氏筛好处就是没有重复的筛去同一个合数.
原理:这个筛法所有的合数只能被它最小的素数约数筛去,比如6被2筛去而不是3.
大家看代码和上图可以发现每一次循环对应这上图的一行,以4乘2为例,这一行不会有4乘3那是因为4%2为0直接跳出。12只能被2筛去。
代码
#define N 10005
bool is_prime[N];//记录是否是素数
int prime[N];//储存素数
int ans=0;//记录素数个数
int PRIME() {
memset(is_prime, true, sizeof(is_prime));//现将所有的是认为是素数便于之后筛选
is_prime[0] = false;//取消0,1的标记
is_prime[1] = false;
for (int i = 2; i < N; i++) {
if (is_prime[i])//标记素数
prime[ans++] = i;
for (int j = 0; j < ans && i * prime[j] < N; j = j + 1) {
is_prime[i * prime[j]] = false;
if (i % prime[j] == 0)//这里很有意思,说明只用被筛去数约数中最小的数筛去,相当于只筛一次
break;
}
}
return 0;
}