zoukankan      html  css  js  c++  java
  • 质数的两种常用判断方法——埃氏筛法和欧拉筛法

    1.埃氏筛法:时间复杂度是O(nlognlogn),打表把一定范围内的质数都记录在数组里所以空间复杂度较高。具体的实现是通过两个数组一个prime记录当前范围的质数序号,另一个isprime判断是否是素数,将isprime初始化为1,从i=2开始遍历标记所有i的倍数的数的isprime为零。

    代码:

     1 #include<iostream>
     2 #include<algorithm>
     3 #include<vector>
     4 #include<cstring>
     5 #include<cstdio>
     6 using namespace std;
     7 #define mem(s,n) memset(s,n,sizeof s);
     8 typedef long long ll;
     9 const int maxn=9e2+1;
    10 const int Inf=0x7f7f7f7f;
    11 bool isPrime[maxn];
    12 int primes[maxn];
    13 //当然,当数据太大导致普通数组存不下的时候,可以采用stl里的vector来存
    14 int cnt;
    15 void judgePri()
    16 {
    17     mem(isPrime, 1);
    18     cnt = 0;
    19     isPrime[1] = 0;//1特殊处理 
    20     for (int i = 2; i < maxn; i++) 
    21     {
    22         if (isPrime[i] == 1)
    23         {
    24             primes[cnt++] = i;
    25             for (int j = i; j < maxn; j += i) //标记i在N范围内的所有倍数
    26             {
    27                 isPrime[j] = 0;
    28             }
    29         }
    30     }
    31 }
    32  
    33 int main(void)
    34 {
    35     judgePri();
    36     for (int i = 0; i < cnt; i++)
    37     {   
    38         if(i%9==0) cout<<endl;
    39         printf("%d ", primes[i]);
    40     }
    41     return 0;
    42 }
    View Code

    然而我们会发现一个问题就是有重复标记的情况,举个例子6第一次i=2时就已经标记了但是i=3又遍历了一次,这样其实就是浪费操作了,所以引入一种改进算法欧拉算法。

    2.欧拉算法:时间复杂度O(n),主体思路还是建立在埃氏筛法的基础上,对其重复标记进行了优化。我们很容易想到只用合数中的一个因数筛选掉这个合数。思路实现——利用前面求得的质数,从小到大遍历如果i被prime[j]整除那么跳出循环,同时也把i*prime[j]遍历了标记成合数。(具体实现见代码)

    代码

    #include<iostream>
    #include<algorithm>
    #include<vector>
    #include<cstring>
    #include<cstdio>
    using namespace std;
    #define mem(s,n) memset(s,n,sizeof s);
    typedef long long ll;
    const int maxn=9e2+1;
    const int Inf=0x7f7f7f7f;
    bool isPrime[maxn];
    int primes[maxn];
    int cnt;
    void judgePri() 
    {
        int temp;
        mem(isPrime, 1);
        cnt = 0;
        isPrime[1] = 0;
        for (int i = 2; i < maxn; i++)
        {
            if (isPrime[i] == 1)
            primes[cnt++] = i;
            //优化
            for (int j = 0; j < cnt && (temp = i * primes[j]) < maxn; j++) //找i之前的所有质数 
            {
                isPrime[temp] = 0;//i * primes[j]肯定是合数,先标记掉 
                if (i % primes[j] == 0)//关键,每次整除一个最小的质数将会跳出循环,所以每个数字,只会被最小的质数筛一次 
                {
                    break;
                }
            }
            //优化 
        }
    }
     
    int main(void)
    {
        judgePri();
        for (int i = 0; i < cnt; i++)
        {   
            if(i%9==0) cout<<endl;
            printf("%d ", primes[i]);
        }
        return 0;
    }
    View Code

     3.常用板子:

     1 int  f[maxn];//f[i]表示i的因子个数
     2 int pri[maxn];
     3 int notpri[maxn];
     4 int prime[maxn];
     5 ll p[maxn]; // p[i] 表示 i由几个素因子组成如 p[6]=2 2*3 p[8]=3 2*2*2
     6 void init(){
     7     now=0;f[1]=1;
     8     notpri[0]=notpri[1]=1;
     9     for(int i=2;i<=maxn-1;i++){
    10         if(!notpri[i])pri[++now]=i,f[i]=2,p[i]=1;
    11         for(int j=1;j<=now&&pri[j]*i<=maxn-1;j++){
    12             notpri[i*pri[j]]=1;
    13             if(i%pri[j]==0){//有pri[j]作为质因子时
    14                 f[i*pri[j]]=f[i]*(p[i]+2)/(p[i]+1);
    15                 p[i*pri[j]]=p[i]+1ll;
    16                 break;
    17             }
    18             f[i*pri[j]]=f[i]*f[pri[j]];//互质则直接乘
    19             p[i*pri[j]]=p[i]+1ll; 
    20         }
    21     }
    22     // rep(i,1,10) {
    23     //     cout<<i<<" "<<p[i]<<endl;
    24     // }
    25     rep(i,1,maxn-1) pre[i]=pre[i-1]+p[i];
    26 }
  • 相关阅读:
    纪念我用word发布的第一篇文章
    第一个SpringMVCHelloWorld
    JSTL学习笔记
    bonecp的使用
    hdu 1556 树状数组
    hdu 1561 树形DP
    MYSQL使用笔记
    Android中简单实现Spinner的数据绑定
    Android中利用Application实现多个Activity间共享数据
    技术到底重要不重要?
  • 原文地址:https://www.cnblogs.com/zpj61/p/13436359.html
Copyright © 2011-2022 走看看