关于筛法
Posted wengsy150943
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了关于筛法相关的知识,希望对你有一定的参考价值。
众所周知,筛法是打素数表的重要方法。基础的筛法也是很容易的,不需要多加赘述。这里提供一个优化的方法。
一般使用的筛法都是埃拉托斯特尼筛法,其代码如下:
void getPrime() {
prime[0]=false;
prime[1]=false;
for (int i=2; i<INT_MAX; i++)
if (prime[i]) {
primes[++cnt ]=i;
for (int k=i*2; k<INT_MAX; k+=i)
prime[k]=false;
}
}
这种筛法简单易懂,但缺点是经常会多筛去合数,最简单的例子就是6,会被2,3分别筛去。当表的规模很大时,这个额外开销是惊人的。
有一些常数级的优化会被应用以减少这种开销,比如特判2后+2进行。改良后的代码如下:
void getPrime() {
prime[0]=false;
prime[1]=false;
prime[2]=true;
tot=0;
for (int i=3; i<INT_MAX; i+=2) //这里间距改为了2
if (prime[i]) {
primes[++tot ]=i;
for (int k=i*3; k<INT_MAX; k+=2*i) //这里的优化似乎比较少人做?事实上i的偶数倍显然是应该被剔除的
prime[k]=false;
}
}
但这种优化并不能一劳永逸地解决问题。于是我又查到一个更有效的筛法,代码如下:
void getPrime(){
prime[0]=1;
prime[1]=1;
tot=0;
for(int i=2;i<MAX;i++){
if(!prime[i])
primes[tot]=i,tot++;
for(int j=0;j<tot&&i*primes[j]<MAX;j++){
prime[i*primes[j]]=1;
if(i%primes[j]==0) break;
}
}
}
有人把它称作欧拉筛法,也有人称为快速线性筛法。它从根本上杜绝了重复筛合数的问题,保证每个合数只会被它最小的质因子筛去。一般情况下这样的效率已经足够了,但我们会发现,对普通筛法的优化在这里还适用。于是继续优化:
void getPrime(){
prime[0]=1;
prime[1]=1;
tot=0;
primes[tot]=2;
tot++;
for(int i=3;i<MAX;i+=2{
if(!prime[i])
primes[tot]=i,tot++;
for(int j=0;j<tot&&i*primes[j]<MAX;j++){
prime[i*primes[j]]=1;
if(i%primes[j]==0) break;
}
}
}
这样折腾一个简单算法的优化也没谁了......
以上是关于关于筛法的主要内容,如果未能解决你的问题,请参考以下文章