素数//素数筛

版权声明:叶小小 https://blog.csdn.net/dy416524/article/details/86431057

枚举所有小于数,看是否它能整除其他自然数,但实际上只需要枚举根号次。

bool Is_prime(int n)
{
    for(int i=1;i*i<=n;++i)
    {
        if(n%i==0) return false;
    }
    return true;
}

埃氏筛:做法其实很简单,首先将2到n范围内的整数写下来,其中2是最小的素数。将表中所有的2的倍数划去,表中剩下的最小的数字就是3,他不能被更小的数整除,所以3是素数。再将表中所有的3的倍数划去……以此类推,如果表中剩余的最小的数是m,那么m就是素数。然后将表中所有m的倍数划去,像这样反复操作,就能依次枚举n以内的素数,这样的时间复杂度是O(nloglogn)。

欧拉筛:欧拉筛法的基本思想 :在埃氏筛法的基础上,让每个合数只被它的最小质因子筛选一次,以达到不重复的目的。其他复杂度(O(n).

#include <iostream>
#include <bits/stdc++.h>
using namespace std;
bool Is_prime(int n)//普通判断素数
{
    for(int i=1;i*i<=n;++i)
    {
        if(n%i==0) return false;
    }
    return true;
}
#define maxn 10000000
bool vis[maxn];
int prime[maxn],x;
void isprime(int n) //埃氏筛
{
    for(int i=2;i<=n;i++)
    {
        if(!vis[i]) prime[x++]=i;
        for(int j=2;j*i<=n;j++)
        {
            vis[i*j]=true;
        }
    }
}
void oulasai(int n)  //欧拉筛
{
    for(int i=2;i<=n;i++)
    {
        if(!vis[i]) prime[x++]=i;
        for(int j=0;j<x;j++)
        {
            if(i*prime[j]>n) break;
            vis[i*prime[j]]=true;
            if(i%prime[j]==0) break;
        }
    }
}
int main()
{
    int n;
    scanf("%d",&n);
    oulasai(n);
    for(int i=0;i<x;i++)
        printf("%d\n",prime[i]);
    return 0;
}

欧拉筛的难点就在于对if (i % prime[j] == 0)这步的理解,当i是prime[j]的整数倍时,记 m = i / prime[j],那么 i * prime[j+1] 就可以变为 (m * prime[j+1]) * prime[j],这说明 i * prime[j+1] 是 prime[j] 的整数倍,不需要再进行标记(在之后会被 prime[j] * 某个数 标记),对于 prime[j+2] 及之后的素数同理,直接跳出循环,这样就避免了重复标记。
比如我们求20以内的素数,

2 是 。排除4,2整除2,跳出;

3是。 排除6,3不整除2,继续,排除9,3整除3,跳出。

4不是,但继续执行,排除8,4整除2,跳出。

5是。 排除10,15,25;

6不是。继续执行,排除12,18,30;

可见如果4处不跳出循环,12就会被筛两次。

米勒罗宾素数检测法:基于随机算法,可以在O(logn)内判断一个数是否是素数,但存在一定的误差。

放假回去看看https://paste.ubuntu.com/p/8YX9FjC5Zf/

猜你喜欢

转载自blog.csdn.net/dy416524/article/details/86431057