1. 程式人生 > >算法——素數問題全解

算法——素數問題全解

重復 flag img 自己實現 運行 height sin 題目 fff

1.線性素數篩(試除法)

適用範圍:判定數據不大,數據量級別較小(一般超過10000就要慎重了)。

一般來說,“素數判定” 對這道題目來說只是輔助的話,用這個方法就可以過的。

int Isprime(int x) {
    //素數定義為大於1的自然數,不用考慮出現0,1負數的情況
    for (int i = 2; i <= sqrt(x); i++) {
        if (x%i == 0) return 1;
    }
    return 0;
}

題目:HDU 1262

技術分享圖片
#include <iostream>
#include <math.h>
using
namespace std; int Isprime(int x) { //素數定義為大於1的自然數,不用考慮出現0,1負數的情況 for (int i = 2; i <= sqrt(x); i++) { if (x%i == 0) return 1; } return 0; } int main() { int x, y; while (cin >> x >> y) { if (x == 0 && y == 0)break; int flag = 1;
for (int i = x; i <= y; i++) { int n = pow(i, 2) + i + 41; if (Isprime(n)) { flag = 0; break; } } if (flag) cout << "OK" << endl; else cout << "Sorry" << endl; } }
View Code

題目:HDU 2012

這題有點意思,一個偶數 N 可以分成兩個距離 N/2 距離一樣的素數的和。比如:20=7+13

技術分享圖片
#include <iostream>
using namespace std;

int Isprime(int x) {
    int i;
    for (i = 2; i <= sqrt(x); i++) {
        if (x%i == 0) {
            return 1;
        }
    }
    return 0;
}
int main() {
    int n;
    while (cin >> n) {
        int l, r;
        l = r = n / 2;
        while (Isprime(l) || Isprime(r))l--, r++;
        cout << l << " " << r << endl;
    }
    return 0;
}
View Code

2.埃式/歐拉篩(打表法)

適用範圍:數據量級別巨大。例如:N<10^6,問N是第幾個素數、輸出第一百萬個素數(這個更麻煩一些)

  • 埃式篩

技術分享圖片

基本思想:質數的倍數一定不是質數。

int M[1000000];
void AiSieve() {
    int count = 0;
    for (int i = 2; i < 1000000; i++) {
        if (M[i] == 0) {
            M[i] = ++count;
            for (int j = 2 * i; j < 1000000; j += i) {
                M[j] = -1;
            }
        }

    }
}
  • 歐拉篩

基本思想 :在埃氏篩法的基礎上,讓每個合數只被它的最小質因子篩選一次,以達到不重復的目的。

int M[1000001];
int prime[80000];
void EluerSieve() {
    int count = 0;
    for (int i = 2; i <= 1000000; i++){
        if (!M[i]){
            prime[count++] = i;
        }
        for (int j = 0; j < count && prime[j] * i <= 1000000; j++){
            M[i*prime[j]] = -1;
            if (i%prime[j] == 0)
                break;
        }
    }
}

題目:HDU 2136

這題輸出的數據級別太大了,用 cout 是過不了的,坑B,技術分享圖片

技術分享圖片
#include <iostream>
using namespace std;

int M[1000000];

int main() {
    int count = 0;
    for (int i = 2; i < 1000000; i++) {    
        if (M[i] == 0) {
            M[i] = ++count;
            for (int j = 2 * i; j < 1000000; j+=i) {
                M[j] = count;
            }
        }
    }
    int n;
    while (scanf("%d", &n) != EOF) {
            //cout << M[n] << endl;
        printf("%d\n",M[n]);
    }
}
View Code

3.Meisell-Lehmer算法(求2...n範圍內的素數個數)

這裏為什麽是空的呢,因為我還沒看懂。

4.看臉OJ法(Miller - Rabin素數測試)

適用範圍:數值特別大,(C++ 受long long數據範圍限制,穩妥點只能到10^10)

原理費馬小定理_百度百科,簡單來說:假如p是質數,且gcd(a,p)=1,那麽 a(p-1)≡1(mod p)。反過來不一定成立。即當a^(p?1)%p=1ap?1%p=1時,p未必是質數。但是這個概率比較小。所以,做的次數越多,正確率越高,只要出現一次不為1,就一定不是素數。

要做兩點:

1. 打個素數表,方便取 a 的值(但要註意,a不能和p值取相同)。

2. 快速冪,問題就在這,我們要判斷的數,在快速冪裏是mod數,而這個mod通常很大,那麽這句話 a = ((a%mod)*(a%mod)) % mod; 取余的意義其實不大,long long 十進制下19位,mod達到10位,假如正巧不巧,a正好就比mod小一點點,就很可能爆範圍了(但是,我們做上百次檢測,這個可能性就很大了)。

所以這個就很難受,判斷大整數,還做不了太大的,就算能自己實現一個大整數,運行速度上也達不到要求了。

#include <iostream>
#include <math.h>
#include <time.h>
using namespace std;
int M[100001];
int prime[8000];
void EluerSieve() {
    int count = 0;
    for (int i = 2; i <= 100000; i++){
        if (!M[i]){
            prime[count++] = i;
        }
        for (int j = 0; j < count && prime[j] * i <= 100000; j++){
            M[i*prime[j]] = -1;
            if (i%prime[j] == 0)
                break;
        }
    }
}
int fastpower(int down,int up,int mod) {
    long long a=down, res = 1;
    while (up) {
        if (up & 1)
            res = ((res%mod)*(a%mod)) % mod;
        a = ((a%mod)*(a%mod)) % mod;
        up >>= 1;
    }
    return res;
}
int MillerRabin(int x) {
    srand(time(0));
    for (int i = 0; i < 1000; i++) {
        int a = prime[rand()%10000];
        if (a == x) {
            i--;
            continue;
        }
        if (fastpower(a, x - 1, x) != 1) {
            return 0;
        }
    }
    return 1;
}

int main() {
    int N;
    EluerSieve();
while (cin >> N) {
        //cout << M[N] << endl;
        cout << MillerRabin(N) << endl;
    }
}

算法——素數問題全解