• 【数论】埃氏筛法


      这学期的离散数学课程学了一点初等数论,其中的埃氏筛法当时课上没有太懂,课后看了《挑战程序设计竞赛》一书终于弄懂了。(这本书确实很好!算法简洁优美。)

      如果只对一个整数进行素性测试,通常O(√n )的算法就足够了。但如果要对许多整数进行素性测试,则有更为高效的算法,其中就包括埃拉托斯特尼筛法,简称埃氏筛法。它是一个与辗转相除法一样古老的算法,可以用于枚举n以内的素数。

      首先,我们将2到n范围内的所有整数写下来。其中最小的数字2是素数。将表中所有2的倍数都划去。表中剩余的最小数字是3,它不能被更小的数整除,所以是素数。再将表中所有3的倍数都划去。依此类推,如果表中剩余的最小数字是m时,m就是素数。然后将表中所有m的倍数都化去。像这样反复操作,就能依次枚举n以内的素数。

     

    如图所示,最终我们就能得到20以内的所有素数。埃氏筛法的复杂度仅有O(nlognlogn)。对于程序设计竞赛中的数据规模,将它的复杂度看作大致线性的也无妨。下面给出代码: 

     1 #include <iostream>
     2 #include <cstring>
     3 using namespace std;
     4 
     5 //埃氏筛法
     6 
     7 const int MAX_N = 10005;
     8 int prime[MAX_N];  //第i个素数
     9 bool is_prime[MAX_N+1];  //is_prime[i]为true时表示i是素数
    10 
    11 //返回n以内素数的个数
    12 int sieve(int n){
    13     int p = 0;
    14     for(int i = 0; i <= n; i++) is_prime[i] = true;
    15     is_prime[0] = is_prime[1] = false;
    16     for(int i = 2; i <= n; i++){
    17         if(is_prime[i]){
    18             prime[p++] = i;
    19             for(int j = 2*i; j <= n; j+=i) is_prime[j] = false;  //筛去所有素数的倍数
    20         }
    21     }
    22     return p;
    23 }
    24 
    25 
    26 int main()
    27 {
    28     int n;  //枚举n以内素数
    29     while(cin>>n){
    30        int p = sieve(n);
    31         cout<<p<<endl;
    32         for(int i = 0; i < p;i++)
    33             cout<< prime[i]<<" ";
    34         cout<<endl;
    35     }
    36 
    37     return 0;
    38 }
  • 相关阅读:
    Python 2 中的编码
    奇异值分解及其应用
    c#基础系列3---深入理解ref 和out
    c#基础系列2---深入理解 String
    c#基础系列1---深入理解值类型和引用类型
    广州.NET微软技术俱乐部微信群有用信息集锦(10)
    程序员英语二三事(3)
    BDD实战篇
    BDD实战篇
    广州.NET微软技术俱乐部
  • 原文地址:https://www.cnblogs.com/Aikoin/p/10180157.html
Copyright © 2020-2023  润新知