zoukankan      html  css  js  c++  java
  • 浅谈筛素数

    假设一个数N,我们现在要求1-N之间哪些数是素数,那些不是素数?

     下面介绍几种解法(当然打表就免了吧)

    (1)最简单最暴力,也是最慢的解法:

      枚举 2-N/2 之间的所有数试试可不可以与 N 相除没有余数。

      有人说:为啥不枚举N。-----自己悟吧;

    #include<stdio.h>
    int main()
    {
        bool flag;
          int n;
          while(scanf("%d",&n)==1)
          { 
              for(i=2;i<=n/2;i++)if(n%i==0)
              {
                  flag=1;
                  break;
              }
            if(flag==0)printf("YES
    ");
            else  printf("NO
    ");
          }
    }

    (2)最普通最常见的解法:

      枚举 2-sqrt(N) 之间的所有数试试可不可以与 N 相除没有余数。

      为什么要枚举到sqrt(N)呢?

      证明:因为对一个数n,如果他能分解成n=pq,那么pq里必然有一个大于等于根号n一个小于等于根号n,也就是说一个合数必然有一个因子是小于等于根号n的,所以对一个数n,只要检验他有没有小于等于根号n的因子就可以了。

      所以代码就好写了.

    #include<cstdio>
    #include<cmath>
    using namespace std;
    int main()
    {
        bool flag;
        int n,x;
        while(scanf("%d",&n)==1)
        {
            x=sqrt(n);
            for(i=2; i<=x; i++)
                if(n%i==0)
                {
                    flag=1;
                    break;
                }
            if(flag==0)printf("YES
    ");
            else  printf("NO
    ");
        }
    }

    (4)普通筛选法--埃拉托斯特尼筛法:

      听名字,哇哦,如此高大上,一定特别好用吧;

      WOC!枚举每一个质因子,能与它乘的都记录为不是。

      基本思想:素数的倍数一定不是素数
      
    实现方法:用一个长度为N+1的数组保存信息(0表示素数,1表示非素数),先假设所有的数都是素数(初始化为0),从第一个素数2开 始,把2的倍数都标记为非素数(置为1),一直到大于N;然后进行下一趟,找到2后面的下一个素数3,进行同样的处理,直到最后,数组中依然为0的数即为素数。

      说明:整数1特殊处理即可。

      prime[]用来保存得到的素数 prime[] = {2,3,5,7,11,.........} tot 是当前得到的素数的个数 check :0表示是素数  1表示合数。

    memset(check, 0, sizeof(check));
    int tot = 0;
    for (int i = 2; i <= n; ++i)
    {
      if (!check[i])
      {
        prime[tot++] = i;
      }
      for (int j = i+i; j <= n; j += i)
      {
        check[j] = 1;
      }
    }

      目测或者手动模拟的话,明显有许多冗余(就是重复的操作),会消耗不少时间。

      有没有啥其他的改进方法呢?----下面有请出我们的欧拉吧。

    (4)欧拉线性筛:

    #include<cstdio>
    #include<cstring>
    using namespace std;
    int prime[];
    int check[];
    int tot = 0;
    memset(check, 0, sizeof(check));
    for (int i = 2; i < MAXL; ++i)
    {
        if (!check[i])prime[tot++] = i;
        for (int j = 0; j < tot; ++j)
        {
            if (i * prime[j] > MAXL)break;    //超过了要所求的数,计算就没必要了; 
            check[i*prime[j]] = 1;            //可以被乘出来,就一定不是素数咯。 
            if (i % prime[j] == 0)break;    //这个数被它%等于0了,说明已经出现了重复,break。 
        }
    }
    // check中没有被标记过的就是素数咯。 

    prime[]数组中的素数是递增的,当i能整除prime[j],那么i*prime[j+1]这个合数肯定被prime[j]乘以某个数筛掉。因为i中含有prime[j],prime[j]比prime[j+1]小,即i=k*prime[j],那么i*prime[j+1]=(k*prime[j])*prime[j+1]=k’*prime[j],接下去的素数同理。所以不用筛下去了。因此,在满足i%prime[j]==0这个条件之前以及第一次满足改条件时,prime[j]必定是prime[j]*i的最小因子。

    除特别注明外,本站所有文章均为Manjusaka丶梦寒原创,转载请注明来自出处

  • 相关阅读:
    vim配置文件
    NGUI屏幕自适应解决方案
    配置java环境
    Ignore files which are already versioned
    Unity3D TestTool Part _1
    c# 语法
    Application.persistentDataPath 的一个小坑
    Unity3D Log 收集机制
    Android 问题流水总结
    Open Phone, SMS, Email, Skype and Browser apps of Android in Unity3d
  • 原文地址:https://www.cnblogs.com/rmy020718/p/8832517.html
Copyright © 2011-2022 走看看