埃拉托斯特尼筛法:
质朴的算法:
确认质数:从2开始,从小到大找第一个未被筛去的数
筛去合数:确认是质数之后,筛去质数的所有倍数
因此程序大概就是
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
记得小学课本学“素数”的时候就有类似的图:
一张10*10的数表,从2开始,从小到大找第一个未被划斜杠的数,之后将其的倍数全部杠掉
(缺图)
很快就会发现,2筛去了一半的数,而之后的偶数几乎都被筛去了很多次(类似于鞭尸。。),也就是说,花费了很多无用的时间来筛去已经被筛过的数
于是我们很容易就会想到这样的优化:当当前”筛子“不为2时,每次隔1个数筛一个
以此类推,隔2个隔3个……
于是最终就可以迭代到欧拉筛法:
欧拉筛法:
“思想是 使每个数只被其最小质因数所筛去 ”
讲起来简单,但却不好实现
一种实现的办法是:
之前的埃筛法中,只有素数可以当筛子,因为判定素数和筛除操作是一起执行的
我们知道,所谓合数,也就是可以表达成素数幂之积
如:6174=2*3*3*7*7*7
按照欧拉筛法的思想,应该使得6174被2筛去,但是如果合数也可以做筛子:
那么可以让6174被3087筛去
3087被1029筛去
1029被343筛去
343被49筛去
49被7筛去
7没有被比它小的数所筛去,可以确定7是素数
也就是说,如果每个素数筛去 该素数与 不大于它的素数 之积,合数筛去 该合数与 不大于它最小质因子 的素数 之积,就可以不重复不遗漏(类似于数学归纳法)
举例:
2做筛子,筛去4
3做筛子,筛去6,9
4做筛子,筛去8
5做筛子,筛去10,15,25
6做筛子,筛去12
7做筛子,筛去14,21,35,49
8做筛子,筛去16
9做筛子,筛去18,27
10做筛子,筛去20
11做筛子,筛去22,33,55,77,121
12做筛子,筛去24
13做筛子,筛去26,39,65,91,143,169
14做筛子,筛去28
15做筛子,筛去30,45
16做筛子,筛去32
17做筛子,筛去34,51,85,119,187,221,289
……大概就是这样子
因此:
确认质数:从2开始,从小到大找第一个未被筛去的数
筛去合数:每个数都筛去 它与 不大于它的素数 之积,如果这个数是合数,则发现其第一个因子的时候停止筛除操作
代码如下
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 for(int i=2; i<=MAX; ++i) { 2 if(!number[i]) 3 prime[++ctprime]=i; 4 else 5 for(int ii=1; i*prime[ii]<=MAX && ii<=ctprime; ++ii) { 6 number[i*prime[ii]]=true; 7 if(i%prime[ii]==0) 8 break; 9 } 10 } 11 // bool number[MAX]= {1,1,0};//0为素数,MAX为数据规模 12 // int prime[]= {0,2};//这个数组可以比MAX小很多 13 // int ctprime;//初始值为0
![](https://images.cnblogs.com/OutliningIndicators/ContractedBlock.gif)
1 for(int i=2; i<=MAX; ++i) { 2 if(!number[i]) {//优化:素数一定可以筛到它的平方,减少判断 3 prime[++ctprime]=i; 4 for(int ii=1; ii<=ctprime && i*prime[ii]<=MAX; ++ii) 5 number[i*prime[ii]]=true; 6 } else 7 for(int ii=1; i*prime[ii]<=MAX && ii<=ctprime; ++ii){ 8 number[i*prime[ii]]=true; 9 if(i%prime[ii]==0) 10 break; 11 } 12 }
OVER