zoukankan      html  css  js  c++  java
  • 线性筛法 素数判断优化

      

    判断素数:

    普通的就不说了 

    一种更高效的做法:

    结论是:大于等于5的质数一定和6的倍数相邻

    x≥1x1,将大于等于55的自然数表示如下: ......6x-1,6x,6x+1,6x+2,6x+3,6x+4,6x+5,6(x+1),6(x+1)+1............6x1,6x,6x+1,6x+2,6x+3,6x+4,6x+5,6(x+1),6(x+1)+1......

    可以看到,不在6的倍数两侧,即6x6x两侧的数为6x+2,6x+3,6x+4...6x+2,6x+3,6x+4...由于2(3x+1),3(2x+1),2(3x+2),2(3x+1),3(2x+1),2(3x+2),

    所以它们一定不是素数,再除去6x6x本身,显然,素数要出现只可能出现在6x6x的相邻两侧。

    所以,基于以上条件,我们假如要判定的数为nn,则nn必定是6x-16x1或6x+16x+1的形式,对于循环中6i-16i1,6i6i,6i+16i+1,6i+2,6i+3,6i+46i+2,6i+3,6i+4,其中如果nn能被6i6i,6i+26i+2,6i+46i+4整除,则nn至少得是一个偶数,

    但是6x-16x1或6x+16x+1的形式明显是一个奇数,故不成立;另外,如果nn能被6i+36i+3整除,则n至少能被33整除,

    但是6x6x能被33整除,故6x-16x1或6x+16x+1(即nn)不可能被33整除,故不成立。综上,循环中只需要考虑6i-16i1和6i+16i+1的情况,

    即循环的步长可以定为66,每次判断循环变量kk和k+2k+2的情况即可,代码如下:

    bool Is_prime(int n)
    {
        if(n==1) return false;
        if(n==2||n==3) return true;
        if(n%6!=1&&n%6!=5) return false;
        for(register int i=5;i*i<=n;i+=6)
            if(n%i==0||n%(i+2)==0) return false;
        return true;
    }

    复杂度为:o( sqrt(n)/3 )

    1埃拉托斯特尼筛法(最基本方法)

    思想:素数的倍数一定不是素数  复杂度:O(nloglogn)

    void prime(){
        //1表示不是素数,0表示是素数 
        a[1]=1;//1不是素数 
        for(int i=2;i*i<=k;i++){//枚举到k开方 
            if(a[i]==0){ 
                for(int j=i*i;j<=k;j+=i){
                    //j从i平方开始,每次加i
                    a[j]=1;//这些被穷举到的都不是素数 
                }
            }
        }
    }
    埃拉斯特尼筛法

    通过上述代码,我们发现此方法还可以继续优化,因为上述的方法中,每一个有多组因数可能会被筛多次,例如:3030会被2,3,52,3,5各筛一次导致计算冗余,我们可以对此方法进行改进,得到更加高效的筛法(欧拉筛)

    #include<cstring>
    #incldue<cmath>
    const int MAXN=1000010;
    bool prime[MAXN];
    int Prime[MAXN];
    int num=0;
    void make_prime()
    {
        memset(prime,true,sizeof(prime));
        prime[0]=prime[1]=false;
        for(int i=2;i<=MAXN;i++)
        {
            if(prime[i])
            {
                Prime[num++]=i;
            }
            for(int j=0;j<num&&i*Prime[j]<MAXN;j++)
            {
                prime[i*Prime[j]]=false;
                if(!(i%Prime[j]))
                    break;
            }
        }
        return;
    }
    欧拉筛

    这个方法可以保证每个和合数在N/MN/M的最小素因子时被筛出,所以时间复杂度仅为O(N)O(N)已经可以满足大部分需求,在竞赛中,这种方法也可以在极短的时间内求出关于NN的质数表。

    但是这个算法的弊端在于,为了判断一个大数是否是素数必须从从头开始扫描,而且空间代价也受不了,故不能离散的判断。

  • 相关阅读:
    【Oracle】修改oracle数据库的字符集
    【OS_Linux】Centos7 设置定时任务
    【 DB_Oracle】Oracle多表关联更新
    Java后端技术路线
    【 OS_Linux】centos下查找jdk的安装路径
    【实用工具】Notepad++的主题和字体设置
    【OS_Linux】Linux删除指定日期之前的文件
    【OS_Windows】windows下删除指定日期前的文件
    C#计算一段程序运行时间的三种方法
    Win10 新功能 改变显示器色彩
  • 原文地址:https://www.cnblogs.com/bxd123/p/10526043.html
Copyright © 2011-2022 走看看