【算法】筛质数
目录
- 埃氏筛法
- 算法原理
- 代码
- 欧拉筛法
- 算法原理
- 代码
埃氏筛法
算法原理
算法思想就像"筛子"一样,把合数筛掉,剩下的就是质数:
- 从2开始,依次检查每个数
- 如果当前数未被标记为合数,它就是质数
- 然后把这个质数的所有倍数都标记为合数
- 重复这个过程直到检查完所有数
注意:从i²开始标记:对于质数i,比i²小的倍数(如i×2, i×3,…, i×(i-1))已经被更小的质数标记过了,所以可以从i²开始。
代码
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 1e6+10;
int check[N]; //真为合数 -- 被划掉的数
int prim[N]; //记录质数
int cnt = 0; //质数个数
void aishishai(int n)
{
for(LL i = 2;i<=n;i++)
{
//没被划掉
if(!check[i])
{
prim[++cnt] = i;
for(LL j = i*i;j<=n;j+=i)
check[j] = 1;
}
}
}
int main()
{
int n;cin >> n;
aishishai(n);
cout << cnt;
return 0;
}
欧拉筛法
算法原理
从小到大枚举每个数
- 如果当前数没划掉,记录该质数
- 枚举已经记录的质数(如果合数已越界则中断)
- 合数未越界,则划掉合数
- 条件i%p == 0,保证合数只被最小质因子划掉
- 若i是质数,则最多枚举到自身中断
- 若i是合数,则最多枚举到自身的最小质因子中断
代码
#include <iostream>
using namespace std;
typedef long long LL;
const int N = 1e6+10;
int check[N]; //真为合数 -- 被划掉的数
int prim[N]; //记录质数
int cnt = 0; //质数个数
//欧拉筛
void get_prim(int n)
{
for(int i = 2;i<=n;i++)
{
if(!check[i]) prim[++cnt] = i;
for(int j =1;1ll * i*prim[j] <=n;j++) //越界中断
{
check[i*prim[j]] = 1;
if(i%prim[j] == 0) break;//整除中断
}
}
}
int main()
{
int n;cin >> n;
get_prim(n);
cout << cnt;
return 0;
}