1. 程式人生 > 其它 >c語言學習3(線性篩)

c語言學習3(線性篩)

1.線性篩

尤拉計劃第7題

10001st prime

Problem 7

By listing the first six prime numbers: 2, 3, 5, 7, 11, and 13, we can see that the 6th prime is 13.

What is the 10 001st prime number?



#include <stdio.h>
#define MAX_N 200000int prime[MAX_N + 5] = {0};
void init() {
    for (int i = 0; i < MAX_N; i++) {
        
if (prime[i]) continue; prime[++prime[0]] = i; for (int j = i; j <= MAX_N / i; j++) { prime[j * i] = 1; } } return; } ​ int main() { init(); printf("%d\n", prime[10001]); return 0; }

#include <stdio.h>
#define MAX_N 100int prime[MAX_N + 5
] = {0}; ​ void init() { // i等價於M for (int i = 2; i <= MAX_N; i++) { if (!prime[i]) prime[++prime[0]] = i; // j表示素數表中每一個素數下標 for (int j = 1; j <= prime[0]; j++) { if (prime[j] * i > MAX_N) break; // prime[j]等價於P,prime[j] * i等價於N prime[prime[j] * i] = 1
; if (i % prime[j] == 0) break; } } } ​ int main() { init(); for (int i = 2; i < prime[0]; i++) { printf("%d\n",prime[i]); } return 0; }

關鍵之處在:if(i%prime[j]==0) break;

這句程式碼保證了每個數最多被篩一次,將時間複雜度降到了線性。

證:prime[]陣列中的素數是遞增的,當i能整除prime[j],那麼i*prime[j+1]這個合數肯定會被prime[j]乘以某個數篩掉。因此,這裡直接break掉,將iprime[j+1]及之後的給後面的數去篩。這種方法能保證每個數只被篩一遍,又能保證每個數都被篩到。

為了更好的理解,畫出前面幾次篩的情況

從圖上我們看到,第一列篩掉的是最小素因子是2的數,第二列篩掉的是最小素因子為3的數,依次類推,可以把所有的合數都篩掉。

因為是按照最小素因子篩選,每個數的最小素因數只有一個,所以可以保證每個數都只會被篩一遍。

例如,i=6 時,第一個素數是2,能整除,篩掉12後就break;至於第二個素數3,6x3中的最小素因數肯定是前一個素數2,所以它要到 i=9,素數取2時才被篩掉。

上面的這種 線性篩法 也稱為 Euler 篩法 (尤拉篩法)。

尤拉篩的速度大概是埃氏的3~4倍,然而在小資料中卻有被完爆的可能(因為埃氏篩cache友好?)


100以內數字因子個數

#include <stdio.h>
#define MAX_N 100int prime[MAX_N + 5] = {0};
int f[MAX_N + 5] = {0};
int cnt[MAX_N + 5] = {0};
​
void init() {
    for (int i = 0; i <= MAX_N; i++) {
        if (!prime[i]) {
            prime[++prime[0]] = i;
            f[i] = 2;
            cnt[i] = 1;
        }
        for (int j = 1; j <= prime[0]; j++) {
            if (prime[j] * i > MAX_N) break;
            prime[prime[j] * i] = 1;
            if (i % prime[j] == 0) {
                f[i * prime[j]] = f[i] / (cnt[i] + 1)*(cnt[i] +2);
                cnt[i * prime[j]] = cnt[j] + 1;
                break;
            }
            else
            {
                f[i * prime[j]] = f[i] * f[prime[j]];
                cnt[i * prime[j]] = 1;
            }
        }
    }
    return;
}
​
int main() {
    init();
    for (int i = 2; i <= MAX_N; i++) {
        printf("f[%d]=%d\n",i,f[i]);
    }
    return 0;
}