判断素数或者求出素数的基本算法 《挑战程序设计竞赛》
2018-02-28 11:08
316 查看
2018-2-28
首先我们得明确一个概念,那就是什么是素数,据我的了解,素数就是除了1和它本身之外,不存在其他的因数的数。
1.素性测试
这应该是最简单的了,直接从2至n,如果存在n对其求余为0的话,那就不是素数了,这里可以降低我们的复杂度,想一下,如果一个数i是n的因子,那么n/i也必定是n的因子,不妨设i<=n/i,那么i最大的值就是sqrt(n)了,那么我们的循环也只要从2到sqrt(n)就可以了,因为这个算法比较普遍,我就不附上代码了。
2.埃氏筛法
如果用上面的算法,那么n以内的所有数都要进行一遍素数测试,那么时间复杂度为O(n^2),可想而知这样的效果不是特别好。
对于2而言,2的倍数4,6,8…那就都不是素数了,
对于3而言,3的倍数6,9,12…那也都不是素数了,
如果当前的数m是素数,那么m的倍数就都不是倍数了,有的人可能会问,为什么m就是素数呢,我们想一下如果m不是素数的话,那么它一定可以表示为p*q的积,不妨我们设这里的p为素数(如果p不是素数还可以再拆,直至变为素数),那么我们在遇到p这个素数的时候,就已经把m,这个素数p的倍数划掉了,所以这样反复操作就能得到我们要的素数了。
这里的j有的人可能会想从2*i开始,其实从2*i到(i-1)*i都已经在’i’为2到i-1的时候被计算过了,所以我们这里会选择从i*i开始。
3.区间筛法
对于[a,b)内的合数而言,它们的因子应该在2到sqrt(b)之间,那么我们只要把2到sqrt(n)的倍数在给定区间[a,b)的数筛掉就可以了,为了节省我们的存储空间,我们可以将[a,b),左移到[0,b-a)就可以了。
4000
除此之外还有其他素数有关的算法,不过程序设计竞赛主要就是涉及这三种。
最后给一个第八届蓝桥杯b组的试题:
如果我没记错的话,当时比赛的时候好像是错的。。。
首先我们需要把1000000以内的所有素数筛选出来,这样可以简化我们后边的计算,然后我们对d以及首项a1进行遍历,然后依次判断即可。
刚开始的时候我还在纠结一个问题,也就是说如果当前的cnt正好等于M=10,那么是否存在a1-d正好也是素数,那么这里是不是就多了一个了,变成M+1个了,后来我发现,不存在的,在我这里,以a1-d为首项的等差数列的d’一定小于d。
虽然运行的时候停顿了一下,但是最后还是得到了结果210。
首先我们得明确一个概念,那就是什么是素数,据我的了解,素数就是除了1和它本身之外,不存在其他的因数的数。
1.素性测试
判断给定的数n是否是素数
这应该是最简单的了,直接从2至n,如果存在n对其求余为0的话,那就不是素数了,这里可以降低我们的复杂度,想一下,如果一个数i是n的因子,那么n/i也必定是n的因子,不妨设i<=n/i,那么i最大的值就是sqrt(n)了,那么我们的循环也只要从2到sqrt(n)就可以了,因为这个算法比较普遍,我就不附上代码了。
2.埃氏筛法
求出给定整数n以内有多少个素数
如果用上面的算法,那么n以内的所有数都要进行一遍素数测试,那么时间复杂度为O(n^2),可想而知这样的效果不是特别好。
对于2而言,2的倍数4,6,8…那就都不是素数了,
对于3而言,3的倍数6,9,12…那也都不是素数了,
如果当前的数m是素数,那么m的倍数就都不是倍数了,有的人可能会问,为什么m就是素数呢,我们想一下如果m不是素数的话,那么它一定可以表示为p*q的积,不妨我们设这里的p为素数(如果p不是素数还可以再拆,直至变为素数),那么我们在遇到p这个素数的时候,就已经把m,这个素数p的倍数划掉了,所以这样反复操作就能得到我们要的素数了。
#include<iostream> #include<cstring> using namespace std; const int N = 100; bool is_prime[N+1]; int prime[N+1]; int main(){ memset(is_prime,true,sizeof(is_prime)); is_prime[0]=false;is_prime[1]=false; int cnt=0; for (int i=2;i<=N;i++){ if (is_prime[i]){ prime[cnt++]=i; for (int j=i*i;j<=N;j+=i){ is_prime[j]=false; } } } for (int i=0;i<cnt;i++){ cout<<prime[i]<<" "; } cout<<"cnt="<<cnt<<endl; // for (int i=2;i*i<=N;i++){ // if (is_prime[i]){ // for (int j=i*i;j<=N;j+=i){ // is_prime[j]=false; // } // } // } // int cnt=0; // for (int i=0;i<=N;i++){ // if (is_prime[i]) prime[cnt++]=i; // } // for (int i=0;i<cnt;i++){ // cout<<prime[i]<<" "; // } // cout<<"cnt="<<cnt<<endl; return 0; }
这里的j有的人可能会想从2*i开始,其实从2*i到(i-1)*i都已经在’i’为2到i-1的时候被计算过了,所以我们这里会选择从i*i开始。
3.区间筛法
给定区间[a,b),求出他们两个数之间素数的个数
对于[a,b)内的合数而言,它们的因子应该在2到sqrt(b)之间,那么我们只要把2到sqrt(n)的倍数在给定区间[a,b)的数筛掉就可以了,为了节省我们的存储空间,我们可以将[a,b),左移到[0,b-a)就可以了。
#include<iostream> #include<cstring> using namespace std; typedef long long int ll; const int N = 1000000; bool is_prime_small[N+1],is_prime[N+1]; ll a,b; int main(){ while (cin>>a>>b){ memset(is_prime,true,sizeof(is_prime)); memset(is_prime_small,true,sizeof(is_prime_small)); is_prime_small[0]=false;is_prime_small[1]=false; if (a==0){ is_prime[0]=false; is_prime[1]=false; }else if (a==1){ is_prime[0]=false; } for (ll i=2;i*i<b;i++){ if (is_prime_small[i]){ for (ll j=i*i;j<b;j+=i){ if (j>=a) is_prime[j-a]=false; //在对应区间的数就不是素数了 } for (ll j=i*i;j*j<b;j+=i) is_prime_small[j]=false; //将[2,sqrt(b))内的素数筛出来 } } int cnt=0; for (ll i=0;i<b-a;i++){ if (is_prime[i]){ cnt++; cout<<i+a<<" "; } } cout<<"cnt="<<cnt<<endl; } return 0; }
4000
除此之外还有其他素数有关的算法,不过程序设计竞赛主要就是涉及这三种。
最后给一个第八届蓝桥杯b组的试题:
2,3,5,7,11,13,....是素数序列。 类似:7,37,67,97,127,157 这样完全由素数组成的等差数列,叫等差素数数列。 上边的数列公差为30,长度为6。 2004年,格林与华人陶哲轩合作证明了:存在任意长度的素数等差数列。 这是数论领域一项惊人的成果! 有这一理论为基础,请你借助手中的计算机,满怀信心地搜索: 长度为10的等差素数列,其公差最小值是多少? 注意:需要提交的是一个整数,不要填写任何多余的内容和说明文字。
如果我没记错的话,当时比赛的时候好像是错的。。。
首先我们需要把1000000以内的所有素数筛选出来,这样可以简化我们后边的计算,然后我们对d以及首项a1进行遍历,然后依次判断即可。
刚开始的时候我还在纠结一个问题,也就是说如果当前的cnt正好等于M=10,那么是否存在a1-d正好也是素数,那么这里是不是就多了一个了,变成M+1个了,后来我发现,不存在的,在我这里,以a1-d为首项的等差数列的d’一定小于d。
#include<iostream> #include<cstring> using namespace std; const int N = 1000000, M = 10; bool is_prime[N+1]; int main(){ memset(is_prime,true,sizeof(is_prime)); for (int i=2;i*i<=N;i++){ if (is_prime[i]){ for (int j=i*i;j<=N;j+=i){ is_prime[j]=false; } } } int i,cnt; bool flag=false; for (i=2;;i++){ for (int j=2;j<=N;j++){ if (!is_prime[j]) continue; cnt=1; for (int k=j+i;k<=N;k+=i){ if (!is_prime[k]||cnt>M) break; if (is_prime[k]){ cnt++; } } if (cnt==M){ flag=true; break; } } if (flag) break; } cout<<i<<endl; return 0; }
虽然运行的时候停顿了一下,但是最后还是得到了结果210。
相关文章推荐
- 基本算法 素数判断 java
- JAVA基本算法面试题:2判断并输出素数
- 如何实现“比较两张图片的相似度”,或者说“比较两张图片是否基本一致”的算法?
- 简单的算法题,包括1.打印100——200之间的的素数2.输出乘法口诀表3.判断1000年——2000年之间的闰年,给出完整代码
- 算法提高 ADV-91 素数判断
- 大素数判断和素因子分解(miller-rabin,Pollard_rho算法)
- 判断一个数是否是素数的两种算法
- 快速判断素数算法
- 大素数判断和素因子分解(miller-rabin,Pollard_rho算法)
- 算法:从键盘循环输入一个整数,判断是否是素数\质数
- java经典算法_002判断素数
- 蓝桥杯 ADV-91 算法提高 素数判断
- 素数判断算法(高效率)
- 素数判断算法-----应用
- 算法总结:判断一个数是否为素数
- 判断素数算法的改进
- 大素数判断和素因子分解(miller-rabin,Pollard_rho算法)
- 利用Java判断一个数是否是素数的算法
- 素数判断算法(高效率)
- java经典算法2_判断素数