筛法求素数(质数)
-
试除法 O(√n)
bool isPrime (int x) //x是否为素数 { for (int i = 2; i < x; i++) { if (x % i == 0) return false; } return true; }
改进:
寻找x是否存在新的因子,设新的因子为a, 则可求出另一个为b
x = a * b; 令 a <= b
b = x /a;
所以,a的范围最大和b相等。即,a最大为sqrt (x)。//需要#include <cmath>
bool isPrime (int x) //x是否为素数 { for (int i = 2; i <= sqrt(x); i++) //或写成 i * i <=x { if (x % i == 0) return false; } return true; }
-
埃氏筛法 O (n logn)
首先是素数的Def:
一个大于1的自然数,除了1和它自身外,不能整除其他自然数的数叫素数;否则叫合数。
每个合数都可以写成几个质数相乘的形式,这几个质数就叫做这个合数的质因数。
唯一分解定理:
任何一个大于1的自然数N,若N不为质数,那么N可以唯一分解成有限个质数的乘积。
埃氏筛法:
根据定义可以得到,合数是某个质数的倍数。那么在数表中,把质数的倍数都去掉,剩下的就都是质数了(得到质数表)
#include <iostream> #include <cstring> //memset() using namespace std; //等价于flag 相当于标记作用 bool isPrime[100000005] ; //把下标当作数字(范围) //isPrime[x] true:x是质数 false: x不是质数 //正确标记n以内数字的质数状态,得到质数表 void aiPrime(int n) { memset(isPrime, true, sizeof(isPrime)); //初始化全为true,后续把质数的倍数判断为false isPrime[0] = isPrime[1] = false; //特殊情况 for(int i = 2 ; i <= n; i++) { if (isPrime[i]) //是质数,将质数的倍数筛出去 { for( int j = 2; i * j <=n; j++) { isPrime[i *j] = false; } } } } int main() { int n, cnt = 0; cin >> n; aiPrime(n); //调用后isPrime[]中质数都为true,合数都为false for (int i = 1; i <= n; i++) { if(isPrime[i]) cnt++; } cout << cnt; //输出质数个数 return 0; }
-
欧拉筛法 (接近 O(n)
在埃氏筛法中,不同质数的合数可以是同一个,所以在筛选时会有重复。
根据唯一分解定理,只要能唯一地构造出质数序列乘积,每个合数只筛选一次,就是欧拉筛法。
x = a * b * c (a b c的排列方式多样
则规定 a <= b < = c,由此唯一确定一个序列
若存在质数P
P * i = P * a * b * c,有 P <= a <= b <= c,即质数P小于等于i的最小质因子
| i | 质数表 | 筛除的合数 |
| 2 | {2} | 2 * 2 = 4 |
| 3 | {2, 3} |
2 * 3 = 6 3 * 3 = 9 |
| 4(2 * 2) | {2, 3} |
2 * (2 * 2) = 8 |
| 5 | {2, 3, 5} |
2 * 5 = 10 3 * 5 = 15 5 * 5 = 25 |
| 6(2 * 3) | {2, 3, 5} | 2 * (2 * 3) = 12 |
| 7 | {2, 3, 5, 7} | {14, 21, 35, 49} |
| 8(2 * 2 * 2) | {2, 3, 5, 7} | 2 * (2 * 2 * 2) = 16 |
| 9(3 * 3) | {2, 3, 5, 7} | {18, 27} |
#include <iostream> #include <cstring> //memset() using namespace std; int prime[100000005]; //存放过程中找到的质数(质数表) bool isPrime[100000005]; // 标记数组 int erla(int n) { memset(isPrime, true, sizeof(isPrime)); isPrime[0] = isPrime[1] = false; int cnt = 0; for(int i = 2; i <= n; i++) { if(isPrime[i]) { prime[cnt] = i; cnt++; //与上一行可写成 prime[cnt++] = i; } //构造质数序列, 质数P * i , P <= i的最小质因子 for(int j = 0; j < cnt && prime[j] * i <= n; j++) { isPrime[prime[j] * i] = false; if(i % prime[j] == 0) //判断p是否 <= i的最小质因子 break; } } return cnt; } int main() { int n; cin >> n; cout << erla(n); return 0; }

浙公网安备 33010602011771号