一、原式版本
bool is_prime(int n) { for(int i = 2; i < n; i++) { if(n % i == 0) return false; } return true; } int main() { int n = 0, ans = 0; scanf("%d", &n); for(int i = 2; i < n; i++) { if(is_prime(i)) ans++; } printf("%d", ans); return 0; }
二、境界一:对于枚举法的优化
①优化1
for(int i = 3; i < n; i+= 2) { if(is_prime(i)) ans++; }
显而易见,偶数不可能是质数,所以在枚举的时候,可以一次“走两步”
②优化②
bool is_prime(int n) { for(int i = 2; i * i <= n; i++) // 别忘了等于号了 { if(n % i == 0) return false; } return true; }
如果A不为质数,那么必然存在A=B*C(2<=B<C<A)。所以只要说明B的存在就可以说明A必然是合数。而B最大值 为根号A,所以只要枚举到 i * i<=A即可判断是否为质数。
三、境界二:埃氏筛法
#include <stdio.h> #include <stdlib.h> typedef long long ll; int main() { int n = 0, ans = 0; scanf("%d", &n); bool* f = (bool *)calloc(n + 1, sizeof(bool)); f[1] = 1; for(int i = 2; i < n; i++) { if(!f[i]) { ans++; for(ll j = (ll)i * i; j < n; j+= i) { f[j] = 1; } } } printf("%d", ans); }
在这里只是呈现各种优化思路,详细讲解请参考相关博文 素数筛选——枚举法+埃氏筛法+欧拉筛法(C语言实现)
四、境界三:欧拉筛法
int main() { int n = 0; scanf("%d", &n); bool* flag = (bool*)calloc(n, sizeof(bool)); int cnt = 0; int prime[n+1]; for (int i = 2; i < n; i++) { if (!flag[i]) { prime[++cnt] = i;//prime数组记录素数 } for (int j = 1; i * prime[j] < n; j++)//筛去合数 { flag[i * prime[j]] = 1; if (i % prime[j] == 0)//精髓 break; } } printf("%d", cnt); }
在这里只是呈现各种优化思路,详细讲解请参考相关博文 素数筛选——枚举法+埃氏筛法+欧拉筛法(C语言实现)