• 筛法求素数


    线性筛法求素数:

    基本思想是:把从1开始的、某一范围内的正整数从小到大顺序排列, 1不是素数,首先把它筛掉。剩下的数中选择最小的数是素数,然后去掉它的倍数。依次类推,直到筛子为空时结束。

    cnt=0;
    void make_prime()  {      
        memset(prime, 1, sizeof(prime));
        prime[0]=false;     
        prime[1]=false;     
        int N=31700;      
        for (int i=2;  i<N;  i++)         
          if (prime[i]) {          
            primes[++cnt ]=i;     
            for (int k=i*i; k<N; k+=i)        
                prime[k]=false;       
          }      
        return;
    }   

    此方法效率不高:比如10,在i=2的时候,k=2*15筛了一次;在i=5,k=5*6 的时候又筛了一次。

    快速线性筛法:

    #include<iostream>
    using namespace std;    
    const long N = 200000;   
    long prime[N] = {0},num_prime = 0;    
    int isNotPrime[N] = {1, 1};   
    int main()    
    {     
             for(long i = 2 ; i < N ; i ++)       
               {            
            if(! isNotPrime[i])               
                 prime[num_prime ++]=i;  
            //关键处1        
            for(long j = 0 ; j < num_prime && i * prime[j] <  N ; j ++)
                {               
                      isNotPrime[i * prime[j]] = 1;  
                  if( !(i % prime[j] ) )  //关键处2                  
                    break;           
            }        
        }        
        return 0;   
    }  

    首先,先明确一个条件,任何合数都能表示成一系列素数的积。

    不管 i 是否是素数,都会执行到“关键处1”,


    ①如果 i 都是是素数的话,那简单,一个大的素数 i 乘以不大于 i 的素数,这样筛除的数跟之前的是不会重复的。筛出的数都是 N=p1*p2的形式, p1,p2之间不相等

    ②如果 i 是合数,此时 i 可以表示成递增素数相乘 i=p1*p2*...*pn, pi都是素数(2<=i<=n),  pi<=pj  ( i<=j )

    p1是最小的系数。

    根据“关键处2”的定义,当p1==prime[j] 的时候,筛除就终止了,也就是说,只能筛出不大于p1的质*i。

    我们可以直观地举个例子。i=2*3*5

    此时能筛除 2*i ,不能筛除 3*i

    如果能筛除3*i 的话,当 i' 等于 i'=3*3*5 时,筛除2*i' 就和前面重复了。

    第一种的优化:直接把偶数去掉再筛选;

    我推荐这个算法! 易于理解。 只算奇数部分,时空效率都还不错!
    half=SIZE/2; 
    int sn = (int) sqrt(SIZE); 
    for (i = 0; i < half; i++) 
       p[i] = true;// 初始化全部奇数为素数。p[0]对应3,即p[i]对应2*i+3 
    for (i = 0; i < sn; i++) {    
    if(p[i])//如果 i+i+3 是素数
    {     
        for(k=i+i+3, j=k*i+k+i; j < half; j+=k) 
        // 筛法起点是 p[i]所对应素数的平方 k^2                                        
        // k^2在 p 中的位置是 k*i+k+i
        //    下标 i         k*i+k+i
        //对应数值 k=i+i+3   k^2         
           p[j]=false; 
    } 
    } 
    //素数都存放在 p 数组中,p[i]=true代表 i+i+2 是素数。
    //举例,3是素数,按3*3,3*5,3*7...的次序筛选,因为只保存奇数,所以不用删3*4,3*6....

     根号法:如果一个数X不能被 [2, 根号X ] 内的所有数整除,那么它就是素数

     1 void prime(void)    //素数组打表  
     2 {  
     3   
     4     int tally=2;  
     5     int i,j,flag;  
     6     for(i=5;i<10000;i+=2)  
     7     {  
     8         for(j=0,flag=1;prim[j]*prim[j]<=i;j++)  
     9             if(i%prim[j]==0){flag=0;break;}  
    10         if(flag)  
    11         {  
    12             prim[tally]=i;  
    13             tally++;  
    14         }  
    15     }  
    16     return;  
    17 }  
  • 相关阅读:
    虚方法与非虚方法,native关键字
    Java多态
    Java对象初始化顺序
    继承、初始化
    递归,斐波那契,对象类型数组
    方法重载
    可变形参
    idea
    ss 如何解决margin-top使父元素margin失效
    js中call和apply的用法和区别
  • 原文地址:https://www.cnblogs.com/yoyo-sincerely/p/5021994.html
Copyright © 2020-2023  润新知