有关求质数的思考
求出1到n之间的质数
先写了一个暴力判断的n^(3/2)的算法,虽然加了强力的优化但还是不出意外的挂了。
试试删选法:
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<math.h> int ans[1000005]; int flag[1000005]; int count(int n) { ans[1]=ans[0]=0; int i, j; // 素数数量统计 int count=0; // 初始化素数标记,要高效点咯 flag[2]=1; for (i=3; i<n; i++) { //flag[i]=(i%2!=0)?1:0;//偶数直接值0,奇数值1,2特殊处理,但是这个有判断操作,效率肯定没有直接赋值快,所以用下面的 flag[i++]=1; flag[i]=0; } // n为奇数 if (n%2!=0) flag[n]=1; // 从3开始filter,因为2的倍数早在初始化时代就干掉了 for (i=3; i <= sqrt((double)n); i++) { // i是合数,请歇着吧,因为您的工作早有您的质因子代劳了 if (0 == flag[i]) continue; // 从i的平方倍开始过滤,而不是从前面的已经被其他素数筛掉了,另外变乘法为加法,加法效率比乘法快 for (j=i*i; j <= n; j+=i) flag[j]=0; } // 统计素数个数 for (i=2; i<=n; i++) { if (flag[i]) count++; ans[i]=count; } return count; } int main() { int n,maxn=2,i; for (i=2; i<=1000000; i++) ans[i]=1; count(1000000); while (scanf("%d",&n)) { printf("%d\n",ans[n]); } return 0; }
好吧,又超时了。看来还是需要想更好的方法……
各种找方法之后,我终于从这个博客:
https://blog.csdn.net/code_pang/article/details/7880245
找到了非常强大的方法。这个结论是什么呢?结论就是,如果一个数是素数(大于5),那么它必然在6x的两侧,x为正整数,两侧是指这个数字是6x-1或者6x+1。
现在证明:考虑6x, 6x+1, 6x+2, 6x+3, 6x+4, 6x+5=6(x+1)-1;
6x, 6x+2, 6x+3, 6x+4分别是6,2,3,2,的倍数,故必然不是素数。
所以写出程序如下:
#include<stdio.h> #include<string.h> #include<stdlib.h> #include<math.h> int ans[1000005]; int flag[1000005]; int count=0; int pan(int num) { int i; if (num==1) return 0; if (num==2 || num==3) return 1; if (num%6!=1 && num%6!=5) return 0; for (i=5; i<=sqrt(num); i+=6) { if (num%i==0 || num%(i+2)==0)//用一堆可能是素数的值判断um是不是素数 return 0; } return 1; } int main() { int n,maxn=2,i; for (i=2; i<=1000000; i++) ans[i]=1; for (i=2; i<=1000000; i++) { if (pan(i)==1) count++; ans[i]=count; } //printf("%d\n",count); while (scanf("%d",&n)) { printf("%d\n",ans[n]); } return 0; }
你以为我会AC?对不起,这样还是不够快……于是没办法了……
就在我把上述文字写完发布之后,我突然想到,会不是是我把读入写错了?!改了一下一看,还真是……好吧我把读入写出死循环了,应该写成!=EOF这样子。用删选法试了试,AC了……