• 筛法求素数(2015.7.30)


    质数(prime number)又称素数,有无限个。一个大于1的自然数,除了1和它本身外,不能被其他自然数(质数)整除,换句话说就是该数除了1和它本身以外不再有其他的因数;否则称为合数

    ——百度百科

    要想判断一个数是不是质数,就要看他能不能被除了1和自己之外的数分解

    显然如果当需要多次判断数据是否是素数时,每次都计算一次是很慢的。

    但是可以声明一个布尔型数组,保存对应下标是否为素数,这样只需要计算一次。

    开始时,从2开始,分别乘上2以上的数,所得的数全都不是素数

     

    此部分证明有误

     1 #include <iostream>
     2 #include <string>
     3 #include <cstring>
     4 using namespace std;
     5 bool is_prime[10001];
     6 int main(){
     7     memset(is_prime,true,sizeof(is_prime));
     8     for(int i=2;i<=100;i++){
     9         for(int j=2;j<=100;j++){
    10             is_prime[i*j]=false;
    11         }
    12     }
    13 //    printf("%d",is_prime[4]);
    14     int num;
    15     //cin>>num;
    16     for (num=2;num<100;num++){
    17     if(is_prime[num]==true){
    18         cout<<num<<"是素数"<<endl;
    19     }else{
    20         cout<<num<<"不是素数"<<endl;
    21     }
    22     }
    23     return 0;
    24 }

    显然,对于12,这样既计算了2*6,也计算了6*2(还有3*4,4*3),所以这样重复计算了大量数据

    修改一下算法,可以让运算量稍小。

    合数可以分解成质数相乘,而根据算法,如果一个合数已经被确定,那么由它得出的合数也都被确定。

    所以,如果发现一个数是合数,那么就不必再计算由它乘出的数

    同时,保证相乘的两个数都是前一个小后一个大,这样可以避免同一组数的重复计算。

     Eratosthenes筛法

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cmath>
     4 using namespace std;
     5 const int maxn=10000;
     6 bool is_prime[maxn+1];
     7 int main(){
     8     int m=sqrt(maxn+0.5);
     9     memset(is_prime,true,sizeof(is_prime));
    10     for(int i=2;i<=m;i++){
    11         if(is_prime){
    12             for(int j=i*i;j<=maxn;j+=i){
    13                 is_prime[j]=false;
    14             }
    15         }
    16     }
    17 
    18     for(int num=2;num<100;num++){
    19         if(is_prime[num]==true){
    20             cout<<num<<"是素数"<<endl;
    21         }else{
    22             cout<<num<<"不是素数"<<endl;
    23         }
    24     }
    25     return 0;
    26 }

    然而,如果我们添加一个count变量来记录每个数被重复运算的次数。会发现,仍然有好多数被重复运算。

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cmath>
     4 using namespace std;
     5 const int maxn=10000;
     6 bool is_prime[maxn+1];
     7 int main(){
     8     int count[maxn+1];
     9     memset(count,0,sizeof(count));
    10 
    11     int m=sqrt(maxn+0.5);
    12     memset(is_prime,true,sizeof(is_prime));
    13     for(int i=2;i<=m;i++){
    14         if(is_prime){
    15             for(int j=i*i;j<=maxn;j+=i){
    16                 is_prime[j]=false;
    17                 count[j]+=1;
    18             }
    19         }
    20     }
    21 
    22     for(int num=1;num<100;num++){
    23         if(is_prime[num]==true){
    24             cout<<num<<"是素数"<<endl;
    25         }else{
    26             cout<<num<<"不是素数"<<endl;
    27         }
    28     }
    29 
    30     for(int i=1;i<=maxn;i++)if(count[i]>1)cout<<i<<":"<<count[i]<<endl;
    31     return 0;
    32 }
    点击查看

     

    但是是存在线性的筛法的

    算术基本定理可表述为:任何一个大于1的自然数 N,如果N不为质数,那么N可以唯一分解成有限个质数的乘积N=P1a1P2a2P3a3......Pnan,这里P1<P2<P3......<Pn均为质数,其中指数ai是正整数。这样的分解称为 的标准分解式。最早证明是由欧几里得给出的,现代是由陈述证明。此定理可推广至更一般的交换代数代数数论

    ——百度百科

    只需要计算出所有 i×(小于i的素数) ,那么我们便可以得到所有的合数。同时,通过排除掉i是(小于i的素数)的整倍数的情况来保证只计算一次

     1 #include <iostream>
     2 #include <cstring>
     3 #include <cmath>
     4 using namespace std;
     5 const int maxn=10000;
     6 int main(){
     7     int count[maxn+1]={0};
     8 
     9     int prime[maxn]={0},num_prime=0;
    10     bool isNotPrime[maxn]={1,1};
    11 
    12     for(long i=2;i<maxn;i++){
    13         if(!isNotPrime[i])prime[num_prime++]=i;
    14         for(int j=0;j<num_prime&&i*prime[j]<maxn;j++){
    15             isNotPrime[i*prime[j]]=true;
    16             count[i*prime[j]]++;
    17             if(!(i%prime[j]))break;
    18         }
    19     }
    20 
    21     for(int num=1;num<100;num++){
    22         if(isNotPrime[num]!=true){
    23             cout<<num<<"是素数"<<endl;
    24         }else{
    25             cout<<num<<"不是素数"<<endl;
    26         }
    27     }
    28 
    29     for(int i=1;i<=maxn;i++)if(count[i]>1)cout<<i<<":"<<count[i]<<endl;
    30     return 0;
    31 }

    运行后,可以发现没有每个数运行次数都是1

  • 相关阅读:
    怎么将java项目打包成双击就可以运行的jar包---fatjar
    hdu 2629 Identity Card (字符串解析模拟题)
    求最远点对,输出距离
    poj 2299 求逆序数
    第九周作业 实现图片压缩
    第八周作业 struts,spring,jpa整合简单测试
    第七周作业 POI操作Excel,world文档
    第七周作业 关于xml问题
    第六周作业 略谈jsp
    第六作业 持久层框架mybatis小记
  • 原文地址:https://www.cnblogs.com/ohyee/p/4689610.html
Copyright © 2020-2023  润新知