description
求素数的个数。本题要求编写一个程序,求1~n的素数个数。 要求至少给出两种解法,对于相同的n,给出这两种解法的结果,通过相关数据进行测试,目的是通过对比同一问题不同解法的绝对执行时间体会如何设计“好”的算法。
输入格式:
输入在一行中给出1个整数n(<= 10 000 000)。
输出格式:
对每一组输入,在一行中输出1~n的素数个数。
输入样例1:
5
输出样例1:
3
输入样例2:
14
输出样例2:
6
solution
暴力法
传统方法,从2到n-1依次试,4,5,6测试点超时
#include <stdio.h>
int main(){
int n, count = 0, flag;
scanf("%d", &n);
for(int i = 2; i <= n; i++){
flag = 1;
for(int j = 2; j < i; j++){
if(i%j == 0){
flag = 0;
break;
}
}
count += flag;
}
printf("%d", count);
return 0;
}
开根号法:从2到sqrt(n)均整除判断(原因:素数是因子为1和本身, 如果数c不是素数,则还有其他因子,其中的因子,假如为a,b.其中必有一个大于sqrt© ,一个小于sqrt© 。所以m必有一个小于或等于其平方根的因数,故只验证到其方根即可),5,6测试点依然超时
#include <stdio.h>
#include <math.h>
int main(){
int n, count = 0, flag;
scanf("%d", &n);
for(int i = 2; i <= n; i++){
flag = 1;
for(int j = 2; j <= sqrt(i); j++){
if(i%j == 0){
flag = 0;
break;
}
}
count += flag;
}
printf("%d", count);
return 0;
}
埃氏筛法
- 空间换时间
- 因为一个合数一定能被分解为几个质数的幂的乘积,并且这个数的质因子一定是小于它本身的,所以当我们从小到大将每个质数的倍数都筛去的话,当遍历到一个合数时,它一定已经被它的质因子给筛去了。
但是6测试点超时……
#include <stdio.h>
int hash[10000010] = {0};//初始为全是素数
int main(){
int n, count = 0;
scanf("%d", &n);
for(int i = 2; i <= n; i++){
if(!hash[i]){
count++;
for(int j = 2 * i; j <= n; j += i)
hash[j] = 1;
}
}
printf("%d", count);
return 0;
}
进一步优化,2 * 3我们已经判断过了,就没有必要再判断3 * 2了,因此从i*i开始判断即可
然鹅有时通过,有时测试点6超时……
#include <stdio.h>
const int N = 1e7 + 10;
int hash[N] = {0};//初始为全是素数
int main(){
long long n, count = 0;
scanf("%lld", &n);
for(long long i = 2; i <= n; i++){
if(!hash[i]){
count++;
for(long long j = i * i; j <= n; j += i)
hash[j] = 1;
}
}
printf("%lld", count);
return 0;
}