zoukankan      html  css  js  c++  java
  • 素数筛法

      素数的筛法有很多种,但是基础就是对素数的判定。即,我们需要知道什么是素数,以及素数的一些性质,那么我们先讲一讲素数的性质(这一部分一定要好好掌握,对考试有很大的帮助):

      定义:只有1和自身作为因子(就是因数,不用我再赘述了)的数叫做素数(也叫质数)。

      性质(1):以π(x)表示不超过x的素数个数,可以证明----lim π(x) ln x ÷ x = 1(lim表示x趋近于正无穷)

        根据这一性质,我们可以推得一个式子,它长这样:

             lim π(x) =  x / ln x,

        虽然我暂时还没有用到这个式子,但是听钟神说可以利用这个式子估计算法的复杂度,就先记下来了。

      性质(2):设a是任意大于1的整数,则a的除1以外的最小正约数q必是素数;当a是合数时,q ≤ sqrt( a )

        我们来证明一下:

        我们可以用反证法,假设q不是素数,由q不为一可得q一定是合数,此时,存在q1为q的因子,且满足1 < q1 < q,q1 | q;又因为q |a,这与q是a的除1以外的最小正约数矛盾;

        当a是合数时,设a = a1q,其中q为a的除1以外的最小正约数,则a1 ≥ q,q2 ≤ a,即q ≤ sqrt ( a )  

      性质(3):素数有无穷多个

        下面来证明这个结论:

        用反证法,假设自然数中只有有限多个素数,可以记为P,P,P……Pk ,这时存在一个正整数N = P1P2P……Pk +1,这时由性质(2)可得一定有一个素数P,使得P | N,但是P一定不是已知的素数(否则P | 1),我们就找到了另一个素数,与假设不相符,得证

      

      讲完了这几个性质,我们便可以进行对素数的判别了(这一部分我将结合代码实现讲解)

      筛法一:暴力筛

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstdlib>
     4 #define maxn 10000010
     5 using namespace std;
     6 bool zi_ran_shu[maxn];
     7 bool shai_su_shu(int); //如果这个数是质数,就返回1,否则,就返回0;
     8 int main()
     9 {
    10     int m;
    11     scanf("%d",&m);
    12     for(int i=1;i<=m;++i)
    13         if(shai_su_shu(i)) zi_ran_shu[i]=1;//对每一个小于m的数进行判定,把判定结果存到zi_ran_shu数组里;
    14     for(int i=1;i<=m;++i)
    15         if(zi_ran_shu[i]) printf("%d ",i);
    16     return 0;
    17 }
    18 
    19 bool shai_su_shu(int a)
    20 {
    21     if(a==1) return 0;
    22     if(a==2) return 1; //对1和2的特判
    23     for(int i=2;i<=a-1;++i)//要从i=2开始模拟对a做除法,一直枚举到a-1;
    24         if(a%i==0) return 0;//如果出现可以整除a的数,就说明a不是一个素数,return 0;
    25     return 1;//如果没有找到一个数可以整除a,就说明a是一个素数,return 1;
    26 }

      接下来,思考对这个算法的优化;

      如果没有思路,看看这句话 = = > 结合性质(2),可以想到将筛_素_数函数中的循环改成循环到sqrt(a),这样就完成了优化,这其实就是诶氏筛法

      筛法二:线性筛

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstdlib>
     4 #include<algorithm>
     5 #include<cmath>
     6 #include<iomanip>
     7 #include<cstring>
     8 #include<string>
     9 #define maxn 10000010
    10 using namespace std;
    11 int prime[maxn],tot=0;
    12 bool is_prime[maxn];
    13 int main()
    14 {
    15     memset(is_prime,true,sizeof(is_prime));
    16     int n;
    17     scanf("%d",&n);
    18     for(int i=2;i<=n;++i)
    19     {
    20         if(is_prime[i]==true) prime[tot++]=i;
    21         for(int j=0;j<tot && i*prime[j]<=n;++j)
    22         {
    23             is_prime[i*prime[j]]=false;//对所有质数的倍数进行排除(线性筛主要是减少了这一步的重复)
    24             if(i%prime[j]==0) break;
    25         }
    26     }
    27     for(int i=0;i<=n;++i)
    28     {
    29         if(prime[i]) printf("%d ",prime[i]);
    30     }
    31     return 0; 

       筛法三:Miller-Rabbin素性测试

     1 #include<cstdio>
     2 #include<iostream>
     3 #include<cstdlib>
     4 using namespace std;
     5 int gg[8] = {2,3,5,7,13,29,37,89};
     6 
     7 int kuaisumi(int a,int b,int c){
     8     int ans = 1;
     9     int base = a%c;
    10     while(b){
    11         if(b & 1) ans = (ans*base)%c;
    12         base = (base*base)%c;
    13         b >>= 1;
    14     }
    15     return ans;
    16 }
    17 
    18 bool miller_rabin(int a,int n)
    19 {
    20     int d=n-1,r=0;
    21     while (d%2==0)
    22         d/=2,r++;
    23     int x = kuaisumi(a,d,n);
    24     if (x==1) return true;
    25     for (int i=0;i<r;i++)
    26     {
    27         if (x==n-1) return true;
    28         x=(long long)x*x%n;
    29     }
    30     return false;
    31 }
    32 
    33 bool is_prime(int n)
    34 {
    35     if (n<=1) return false;
    36     for (int a=0;a<8;a++)
    37         if (n==gg[a]) return true;
    38     for (int a=0;a<8;a++)
    39         if (!miller_rabin(gg[a],n)) return false;
    40     return true;
    41 }
    42 
    43 int main()
    44 {
    45     int n;
    46     scanf("%d",&n);
    47     for(int i=1;i<=n;++i)
    48         if(is_prime(i)) printf("%d ",i);
    49     return 0;
    50 }

       先来介绍原理:如果n为素数,取a < n,设n - 1 = d * 2则要么ad ≡ 1(mod n),要么存在0 < i < r ,s.t.ad*2i ≡ -1 ( mod n )

      知道了原理,就可以带进几个数进行计算,得出是否为素数(代码中的gg数组中的几个质数在int范围内不会判断出错),至于代码,也比较好理解,就不再说了。

    这就是本篇博文的所有内容,请大佬们多多指正,不喜勿喷QwQ

    2019-04-09 21:31:23

  • 相关阅读:
    MySQL 之 Metadata Locking 研究
    Spring, MyBatis 多数据源的配置和管理
    ThreadLocal 源码剖析
    Java多线程中的死锁问题
    Java并发基础框架AbstractQueuedSynchronizer初探(ReentrantLock的实现分析)
    PriorityQueue和Queue的一种变体的实现
    被我们忽略的HttpSession线程安全问题
    Java并发之原子变量和原子引用与volatile
    使用Java实现单线程模式
    这些年无处安放的博客
  • 原文地址:https://www.cnblogs.com/juruohqk/p/10679923.html
Copyright © 2011-2022 走看看