基于求素数的数学题
1.首先来看一下如何最快最简单判断一个数是否是素数:
这个大佬的博客写的很好:https://blog.csdn.net/qq_45351611/article/details/120095631?spm=1001.2101.3001.6661.1&utm_medium=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_aa&depth_1-utm_source=distribute.pc_relevant_t0.none-task-blog-2%7Edefault%7ECTRLIST%7ERate-1.pc_relevant_aa&utm_relevant_index=1
1 bool isprime (int num) 2 { 3 if (num<=1) return 0; 4 else if (num==2 || num==3) return 1; 5 else if (num%6!=1 || num%6!=5) return 0; 6 /*因为任何实数都可以表示成6x 6x+1 6x+2 6x+3 6x+4 6x+5的形式 7 (当然也可以表示成5x+c,4x+c之类的,但用6x+c形式表示有更多的公因数可提出) 8 6x+2 6x+3 6x+4 明显就有公因数不可能为素数; 9 则只有6x+1 6x+5的奇数才可能为素数;*/ 10 for (int i=5;i<=num/i;i+=6) 11 if (num%i==0 || num%(i+2)==0) return 0; 12 /*判断num作为6x+1或6x+5形式的奇数是否为素数 13 6x+1 6x+5若有因子,那么因子一定是6x+1 6x+5的形式 14 num%i来判断是否有6x+5形式的因子,num%(i+2)来判断是否有6x+1形式的因子*/ 15 return 1; 16 }
2.接下来看一下看一下在0-n之间的素数如何最快求出:
欧拉筛法:
他是
2.埃氏筛的进化版:
埃拉托斯特尼筛法,利用当前已经找到的素数,从后面的数中筛去当前素数的倍数。
原理:每个大于1的正整数n都可以表示成素数之积的形式。所以在1到n中一个数若不是素数,一定会被筛到。
复杂度:O(n*lglgn),近似为O(n)。
缺点:会重复判断,如果数据很大会不好,如12,在素数2与素数3时就被判了两次;
bool number[maxn+5]; void isprime() { int i,j; memset(number,true,sizeof(number)); for(i=2;i<=maxn;i++) { if(number[i]==true) { for(j=2;j*i<=N;j++) number[i*j]=false; } } }
而欧拉筛法只会遍历各个数一遍:
我们发现每个数都有最小质因数,且只有一个,如12的是2,18的是2,9的是3等等;
利用这个性质有:
1 bool function (int num) 2 { 3 memset(isprime,0,sizeof (isprime)); 4 for (int i=2;i<=num;i++) 5 { 6 if (!isprime[i]) 7 { 8 prime[cnt++]=i; 9 } 10 for (int j=0;j) 11 { 12 isprime[prime[j]*i]=1; 13 /*如果i%prime[j]==0,如果接下来再i*prime[j+1]==num,那被标记的那个数num,并不是由最小质因数标价的 14 因为这表明i中有prime[j]才会i%prime[j]==0,如果i*prime[j+1]=num,这个num 15 会在后面又被标记一次;如:当i==4时,prime中有2,3;如果4*3了==12; 16 又i==6, 在prime[0]==2时,6*2==12,12被重复标记那这个算法与埃式筛法没区别了*/ 17 if (i%prime[j]==0) 18 { 19 break; 20 } 21 } 22 } 23 }