素数筛法
素数是ACM中数论题目常常涉及到得问题。最基本的问题就是如何判断一个数是素数以及如何快速的打出题目涉及范围的素数表。当然数论中关于素数的问题会比较复杂,在这里仅就素数的不同筛法做出总结。
素数,就是只有1和自身两个约数的正整数。2是最小的素数。根据定义,我们就可以直接判断一个数字n是否是素数。优化后的复杂度是O(n*sqrt(n))。至于为什么,我就不做赘述了,自己可以稍作思考。但是,在大规模的数据范围时,这个算法会耗时太多,显得十分低效!不信可以输入n=1000000试试哈~~~~
下面介绍第二种较为高效的算法-----筛法。
具体筛法是:先把n个自然数按次序排列起来。1不是质数,也不是合数,要划去。第二个数2是质数留下来,而把2后面所有能被2整除的数都划去。2后面第一个没划去的数是3,把3留下,再把3后面所有能被3整除的数都划去。3后面第一个没划去的数是5,把5留下,再把5后面所有能被5整除的数都划去。这样一直做下去,就会把不超过N的全部合数都筛掉,留下的就是不超过N的全部质数。因为希腊人是把数写在涂腊的板上,每要划去一个数,就在上面记以小点,寻求质数的工作完毕后,这许多小点就像一个筛子,所以就把埃拉托斯特尼的方法叫做“埃拉托斯特尼筛法”,简称“筛法”。
当然你可以手动操作一下1~30内的筛选过程。
[c-sharp] view plain copy// 1:这是最原始的筛法,还有待优化 #define Max 1000000 bool PRime[Max]; void IsPrime(){ prime[0]=prime[1]=0;prime[2]=1; for(int i=3;i<max;i++) prime[i]=i%2==0?0:1; int t=(int)sqrt(Max*1.0); for(int i=3;i<=t;i++) if(prime[i]) for(int j=i;j<Max;j+=i) prime[j]=0; } //2:优化后的筛法,手动地模拟原始筛法就可以发现,某个数字可能被不止一次地删去 // 优化后的筛法就可以避免这种不必要的删去操作 #define Max 1000000 bool prime[Max]; void IsPrime(){ prime[0]=prime[1]=0;prime[2]=1; for(int i=3;i<max;i++) prime[i]=i%2==0?0:1; int t=(int)sqrt(Max*1.0); for(int i=3;i<=t;i++) if(prime[i]) for(int j=i*i;j<Max;j+=2*i)//优化 prime[j]=0; }
是不是上述优化后的筛法就是最优的呢?记得去年暑期培训的时候博士还给我们介绍了独创的优化,这样在数据规模较大的时候,优化效果显得更明显,可是上级一试哦~~~
[c-sharp] view plain copy//这就是素数的二次筛法,博士独创~~~~~ //与前两种筛法不同,此种筛法中prime[i]=2*i+3(即:我们只存储奇数,偶数肯定不是素数的) #define Max 1000000 bool prime[Max>>1]; void IsPrime(){ memset(prime,true,sizeof(prime)); int n=Max>>1,m=(int)(sqrt(Max*1.0)/2.0); for(int i=0;i<=m;i++) if(prime[i]) for(int j=2*i*i+6*i+3;j<=n;j+=2*i+3) isprime[j]=false; }
博文来源:http://blog.csdn.net/once_hnu/article/details/6302283
新闻热点
疑难解答