一般筛法:
一般筛法:
const int MAXN = 70000;
void Prime() // 筛法求素数表p[i]=1为素数,类似于hash映射!
{
int i, j;
for (i=0; i<MAXN; i++) prime[i] = 1;
prime[0] = prime[1] = 0;
for (i=2; i<MAXN; i++)
{
if (!prime[i]) continue;
for (j=i*2; j<MAXN; j+=i) prime[ j ] = 0;
}
}
线性筛法:
理解if(i%prime[ j ]==0)是关键。
原理:
1. 任何一个合数都可以表示成一个质数和一个数的乘积
2. 假设A是一个合数,且A = x * y,这里x也是一个合数,那么有:
A = x * y; (假设y是质数,x合数)
x = a * b; (假设a是质数,且a < x——>>a<y)
-> A = a * b * y = a * Z (Z = b * y)
即一个合数(x)与一个质数(y)的乘积可以表示成一个更大的合数(Z)与一个更小的质数(a)的乘积!!!!
这也是理解代码中 if(i%primes[j] == 0)break;的关键
例如: 如果i = 8; 那么由于i%2 == 0; 因此对于i=8就只需要检查primes[1]=2即可,因为对于大于primes[1]的质数,像3,有:
8*3 = 2*4*3 = 12*2
也就是说24(8*3=24)并不需要在8时检查,在12时才检查
线性筛法:
#include<iostream>
using namespace std;
const int n=200000;
long prime[n]={0},num_prime=0;//num_pirme记录素数个数
int main()
{
int m;
cin>>m;
int a[n]={1,1},i,j;
for(i=2;i<m;i++)
{
if(!a[i])
prime[num_prime++]=i;
for(j=0;j<num_prime && i*prime[j]<m;j++)
{
a[i*prime[j]]=1;//合数标为1,同时,prime[j]是合数i*prime[j]的最小素因子
if(!(i%prime[j]))//即比一个合数大的质数和该合数的乘积可用一个更大的合数和比其小的质数相乘得到
break;
}
}
for(i=0;i<num_prime;i++)//输出
{
if(i%10==0)printf("\n");
printf("%3d ",prime[i]);
}
printf("\n");
return 0;
}