码迷,mamicode.com
首页 > 其他好文 > 详细

埃氏筛法&欧拉筛法

时间:2019-01-29 21:18:28      阅读:182      评论:0      收藏:0      [点我收藏+]

标签:重复   原理   不可   while   退出   back   amp   ons   freopen   

埃氏筛法

/*
    |埃式筛法|
    |快速筛选素数|
    |15-7-26|
*/
#include <iostream>
#include <cstdio>
using namespace std;
const int SIZE = 1e7;

int prime[SIZE];            // 第i个素数
bool is_prime[SIZE];    //true表示i是素数

int slove(int n)
{
    int p = 0;
    for(int i = 0; i <= n; i++)
        is_prime[i] = true;             //初始化
    is_prime[0] = is_prime[1] = false;      //0,1不是素数
    for(int i = 2; i <= n; i++)
    {
        if(is_prime[i])                //这里比较巧妙, 我只是意会
        {
            prime[p++] = i;             //计算素数的个数,也记录下了素数
            for(int j = 2 * i; j <= n; j += i)      // 除掉了i的倍数的数字
                is_prime[j] = false;
        }
    }
    return p;
}

int main()
{
    int n;
    while(cin >> n)
    {
        int res = slove(n);
        cout << res << endl;
        for(int i = 0; i < res; i++)
            cout << prime[i] << endl;
    }
}

 

2 3 4 5 6 7 8 9 10 11 12
2 3 - 5 - 7 - 9 - 11 -
2 3 - 5 - 7 - - - 11 -

结合这张表看看,慢慢一次次的都筛选完了..

其中最小的素数是2,将表中所有2的倍数都除去,剩下最小的数是3,不能被更小的数整除,所以是素数.再将表中3的倍数的数除去.以此类推.如果表中最小的数字是m,m就是素数.然后将表中所有m的倍数都除去...然后就可以了= =

话说要是求区间[x,y]内求素数个数的话,只要0~y的素数个数-0~x的素数个数就可以了,然后判断x是否为素数就可以了...

 

 

 

欧拉函数

#include <bits/stdc++.h>
using namespace std;
const int maxn = 10000005;

int n, x[maxn], pri[maxn/10], tot, curr, num;//m以内的质数不会m/10个,不放心 || m很小的话可以再开大一点

int main()
{
    //freopen("test.in", "r", stdin);
    scanf("%d%d", &n, &num);
    x[1] = 1;
    for(int i = 2; i != n+1; ++i)
    {
        if(!x[i])
        {
            pri[tot++] = i; //如果一个数是合数那么它一定会在之前被判定出来,故剩下的一定是质数
        }
        for(int j = 0; j != tot; ++j)//当前的所有质数
        {
            curr = pri[j]*i;//一定是合数
            if(curr > n)    break;//超出范围
            x[curr] = 1;//置为合数
            if(i % pri[j] == 0)    break;//重点
        }
    }
    fclose(stdin);
    return 0;
}

 

要说保证某数不被重复判断,关键就在这行代码上。
满足上式时,i是pri[j]的倍数,那么对于后面的pri[k]来说,i * pri[k]就可以被分解为pri[j] * (i / pri[j] *pri[k]),而该数在之前i == pri[j]的时候已经出现过,于是就重复了。直接退出,避免了重复判定。

欧拉筛法固然快,但是也有适用条件,例如求(n, n + 10)中的素数个数的时候,它就明显慢了。由于必须从1开始,所以欧拉筛法的用处在于直接打表而不是求某一段区间。对于这种问题,朴素法未尝不可。

欧拉筛法的原理分析至此结束。

 

 

 

------=====-----=====-----====-----======-------=========================================================

 

埃氏筛法:

从2开始把素数的倍数都给标记掉

欧拉筛法:

把2压到栈/队列中,外面的数可以被栈/队列中的数整除的话,丢掉,不能的话,压入栈/队列中

 

以6为例:

埃氏筛法会遍历到他很多遍

欧拉筛法只会遍历一遍

埃氏筛法&欧拉筛法

标签:重复   原理   不可   while   退出   back   amp   ons   freopen   

原文地址:https://www.cnblogs.com/darlingroot/p/10335790.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!