1. 程式人生 > >素數,埃式篩,尤拉篩

素數,埃式篩,尤拉篩

                                                 素數問題

素數(質數):除了1和它本身沒有其他的因子;

合數:反之

原理:

1.算術基本定理:任何一個大於1的自然數 N,那麼N可以唯一分解成有限個質數的乘積。
2. 若一個數可以進行因數分解,則得到的兩個數一定是有一個>=sqrt(x),另一個<=sqrt(x)。

3.1-N內的素數的個數大約是logN。

素數主要有兩個基本問題:

1.求1—n中的所有素數

2.判斷一個數是否是素數
暴力寫法:

 

#include<bits/stdc++>
#define MAXN 1e5;
bool isprime[MAXN];
bool is_prime(int x)
{
    int flag=0;
    for(int i=2;i<sqrt(x);i++)
    {
        if(x%i==0)
        {
            flag++;
            break;
        }
    }
    if(flag) 
    {
        isprime[x]=false;
        return false;
    }
    else 
    {
        isprime[x]=true;
        return true;
    }
}
 
int init(int N)
{
    int cnt=0;    //記錄素數的個數 
    for(int i=2;i<=N;i++)
    {
        if(is_prime(i))
            cnt++;
    }
    return cnt;
}

埃氏篩

埃拉託斯特尼篩法,利用當前已經找到的素數,從後面的數中篩去當前素數的倍數。

原理:每個大於1的正整數n都可以表示成素數之積的形式。所以在1到n中一個數若不是素數,一定會被篩到。

複雜度:O(n*lglgn),近似為O(n)

缺點:某些數被每個質因子都篩了一遍導致速度減慢。

#define MAXN 1e5
bool isnotprime[MAXN];
int prime[MAXN];
int ant=0;
void init(int N)      //求1到N中所有的素數
{
memset(prime, 0, sizeof(prime));
for(int i =2;i<m;i++)
{
    if (!isnotprime[i])
        {
            prime[ant++]=i;//  prime[0]=2
    for (int k= i*i; k<=N; k+=i)
              isnotprime[k] = 1;
        }

}

尤拉篩

  和埃氏篩法的區別是對於每一個要篩除的數,尤拉篩法只篩除一次。

複雜度:O(n)

 

#include<bits/stdc++.h>
using namespace std;
const int MAXN=100000+5;
bool isprime[MAXN];//isprime[]表示i是不是質數 
int prime[MAXN], tot;//prime[]用來存質數 
void init(int N)
{
    memset(isprime,true,sizeof(isprime)/sizeof(bool)*N);  //初始化所有的數為質數
    for(int i=2;i<=N;i++)
    {
        if(isprime[i]) 
          prime[tot ++] = i;//把質數存起來 
        for(int j=0;j<tot&&i*prime[j]<=N;j++)
        {
            isprime[i*prime[j]]=false;
            if(i%prime[j]==0)  break;//保證每個合數被它最小的質因數篩去 
        }
    }    
}

埃篩和尤拉篩複雜度其實相差不是很多,更推薦埃篩,畢竟好寫很多。