(好-----快------)

素数是什么就不用介绍了吧。。。先介绍判断素数的方法

判断素数

先看朴素算法

for (i=2;i<n;i++)
if (n%i==0) break;
if (i==n) printf(“n is prime”);
else printf(“n is not prime”);

(真的好朴素。。)

用时O(n)

(肯定不行啊,吃枣药丸的。。)

怎么优化呢?

不难发现,如果a是n的约数,那么n/a也是n的约数

所以就有以下代码:

n2=int(sqrt(n)+0.5);
for (i=2;i<=n2;i++) if (n%i==0) break;
if (i>n2) printf(“n is prime”);
else printf(“n is not prime”);

这个用时O(n^0.5)

一般使用的话这样其实差不多了。。(其实有一个更快的只是我不会。。)

筛选素数

进入正题啦!

目标:

尽量快的找出1---n之间的所有素数

朴素算法:

for(int i=2;i<=n;i++)
    {
        for(int j=2;j<=sqrt(i);j++)
        {
            if(i%j==0)
            {
               flag=1;
               break;
            }
        }
        if(!flag)
        cout<<i<<" ";
        flag=0;
    } 

其实也不是很朴素啦。。用了上面介绍的优化,但是速度还是很慢

怎么优化呢?

对于任意数a,a所有的整数倍都是合数

int flag[2333]; int prime[2333]; int primes;
for (int i=2;i<=n;i++) flag[i]=0;
for (int i=2;i<=n;i++) for (int j=i*i;j<=n;j+=i) flag[j]=1; //表示j被标记为合数
for (int i=2;i<=n;i++) if (flag[i]==0) prime[primes++]=i;

有了这个想法,还可以继续优化

对于质数a,a的所有整数倍都是合数

int flag[2333]; int prime[2333]; int primes;
for (int i=2;i<=n;i++)
if (flag[i]==0)
{
    prime[primes++]=i;
    for (int j=i*i;j<=n;j+=i) flag[j]=1;
}

还可以继续优化吗?

其实还可以进一步优化,只要每个合数都只被自己能整除的最小的质数标记一次,速度就可以达到线性级别(好快!)

说白了就是每个质数尽可能多的标记合数(也不是很好懂的样子?)

看代码吧:

#include<iostream>
using namespace std;
int prime[100001];
int f[100001],primes;
int n;
int main()
{
    cin>>n;
    for(int i=2;i<=n;i++)
    {
        if(!f[i])//如果i还没有被标记,就说明i是新出现的素数 
        {
            prime[primes]=i;
            f[i]=-1;
            primes++;//标记 
        }
        for(int j=0;j<primes;j++)//枚举当前找到的所有素数 
        {
            int ans=prime[j]*i;
            if(ans>n)
            break;//越界就停止 
            f[ans]=j+1;//标记每一个含有prime[j] 这个因数的合数 
            if(i%prime[j]==0)//如果当前 i可以整除prime[j],就说明后面的prime[j]都不会是ans的最小质因子了 
            break;
        }
    }
    cout<<primes<<endl;//素数个数 
    for(int i=0;i<primes;i++)
    {
        cout<<prime[i]<<" ";//所有素数 
    }
    return 0;
} 

(RP++!)

02-10 05:47