打开/关闭搜索
搜索
打开/关闭菜单
通知
打开/关闭个人菜单
查看“素数”的源代码
来自吾萌百科
查看
阅读
查看源代码
查看历史
associated-pages
页面
讨论
更多操作
←
素数
因为以下原因,您没有权限编辑本页:
您请求的操作仅限属于该用户组的用户执行:
用户
您必须确认您的电子邮件地址才能编辑页面。请通过
参数设置
设置并确认您的电子邮件地址。
您可以查看和复制此页面的源代码。
若一个正整数无法被除了1和它自身以外的任何自然数整除,则称该数为'''素数(Prime number)''',或称'''质数'''。 在整个自然数集合中,素数的数量不多,分布比较稀疏,对于一个足够大的整数N,不超过N的素数大约有<math>\frac{N}{\ln N}</math>个。 == 质数的判定 == 最简单的方法就是'''试除法''',它作为最简单也最经典的确定性算法,是我们经常会使用的方法。 <syntaxhighlight lang="c" line> int is_prime(n) { if (n < 2) return 0; for (int i = 2; i < sqrt(n); ++i) if (n % i == 0) return 0; return 1; } </syntaxhighlight> === Eratosthenes筛法 === 给定一个整数N,求出1~N之间的所有素数,称为素数的筛选问题。 对于这类问题我们有一种选择是'''Eratosthenes筛法'''。 Eratosthenes筛法基于这样的想法:任意整数x的倍数2x,3x,...都不是素数。根据素数的定义,上述命题显然成立。 我们可以从2开始,由小到大扫描每个数x,把它的倍数标记为合数。当扫描到一个数时,若它没被标记,说明它不能被2~x-1之间的任何数整除,该数就是素数。 <syntaxhighlight lang="c" line> int v[MAX_N]; void eratosthenes(int n) { memset(v, 0, sizeof(v)); for (int i = 2; i <= n; ++i) { if (v[i]) continue; for (int j = i; j <= n/i; ++i) v[i * j] = 1; } } </syntaxhighlight> Eratosthenes筛法的时间复杂度为<math>O(N \log \log N)</math>,该算法实现简单,效率已经非常接近线性,是算法竞赛最常用的素数筛法。 === 线性筛 === 即使在优化后(从<math>x^2</math>开始),Eratosthenes筛法仍然会重复标记合数。 线性筛法通过“从大到小累计素因数”的方式标记每个合数。 设数组v记录每个数的最小素因数,我们按照以下步骤维护v: # 依次考虑2~N之间每个数i。 # 若v[i]=i,说明i是素数,把它保存起来。 # 扫描不大于v[i]的每个素数p,令v[i*p]=p。 每个合数i*p只会被它的最小素因数p筛一次,时间复杂度为<math>O(N)</math>。 <syntaxhighlight lang="c" line> int v[MAX_N], prime[MAX_N]; int m; void primes(int n) { memset(v, 0, sizeof(v)); m = 0; for (int i = 2; i <= n; ++i) { if (v[i] == 0) { v[i] = i; prime[++m] = i; } for (int j = 1; j <= m; ++j) { if (prime[j] > v[i] || prime[j] > m/i) break; v[i * prime[j]] = prime[i]; } } } </syntaxhighlight> == 参考资料 == # 算法竞赛进阶指南,李煜东,134~137页 [[Category:数学]]
返回
素数
。