c語言學習3(線性篩)
阿新 • • 發佈:2021-07-18
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 200000 int 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 100 int 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 100 int 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; }