/*判断n是否为素数*/ for(i=2;i*i<=n;i++) { if(n%i==0) { flag=0;/*flag=0代表n不是素数*/ break; } }
int not_prime[MAXN]={0};/*假定所有数都是素数*/ for(int i=2;i<=sqrt(MAXN);i++) { if(!not_Prime[i]) {/*如果i是素数*/ for(j=i*i;j<=MAXN;j+=i) {/*那么i的倍数全是合数*/ not_prime[i]=1; } } }
对于一个合数,可能被重复筛选多次。
欧拉筛法是埃氏筛法的改进版,大体思路都是先假定所有数都是质数,然后把所有合数去除,留下的都是质数;不同之处就是去除合数的方法,欧拉筛法保证了每个合数只会被它的最小质因数筛去。虽然代码有两重循环,但是因为待求范围内的每个数均只被筛选1次,所以时间复杂度是O(n)。
bool visit[MAXN]={0};/*visit数组存的是待求范围的所有自然数*/ /*visit[1]=0表示1是素数*/ int prime[MAXL]; /*prime数组只存待求范围内的素数*/ /*MAXL可以根据MAXN的大小大致估计一下,MAXN一般是题目给出*/ int cnt=0; /*cnt用来记录素数的个数*/ void getprime(int n) { for(int i = 2;i <= n;i++) { if(!visit[i]) prime[cnt++]=i;/*如果i是素数,就把i标记在prime数组里*/ for(j = 0;i * visit[j] < n && j < cnt;j++) { visit[i * prime[j]] = 1;/*prime数组里面存的素数的i倍,都标记为合数*/ if(i % prime[j] == 0) break;/*关键,看后面的解释*/ } } } `` ### 解释: 为什么说欧拉筛法保证了每个合数只会被它的最小质因数筛去呢? 关键是这一行: ```c if(i % prime[j] == 0) break;
接下来分类讨论一下:
i % prime[j] == 0
的时候break。