标签:大于 正整数 max 两种 name nlog turn 除了 span
素数的定义:除了1和它本身之外,不能被其他整数整除。
一、判定一个正整数n是否为素数的方法:
①定义法:枚举2~n-1这n-2个正整数,如果它们均不能整除n,则可断定n为素数。代码如下:时间复杂度为O(n),如果n为10^9,就不能用此方法。
1 bool is_prime(int n){ 2 if(n==1)return false; 3 for(int i=2;i<n;++i) 4 if(n%i==0)return false; 5 return true; 6 }
②从2开始枚举到不大于sqrt(n)的所有正整数,如果它们均不能整除n,则可断定n为素数。为什么只需枚举到sqrt(n)就可以了呢?理由:假设n存在大于或等于sqrt(n)的因子y,则z=n/y必同时为n的因子,且其值小于或等于sqrt(n)(如果z>sqrt(n),那么z*y>n与n=z*y相矛盾)。所以,若n存在相异于1和它本身的因子y>sqrt(n),则必存在小于或等于sqrt(n)的因子,因此,我们只需测试因子到sqrt(n)即可。时间复杂度为O(sqrt(n))。
1 bool is_prime(int n){ 2 if(n==1)return false; 3 for(int i=2;i*i<=n;++i) 4 if(n%i==0)return false; 5 return true; 6 }
二、给定一个正整数n(n<=10^6),问n以内有多少个素数?如果采用方法2,时间复杂度最坏能达到1e9!!!超时是毫无疑问的,那么是否有比较快速的判断方法呢?于是两种经典筛法就呼啦呼啦地闪亮登场了。
①埃氏筛法:要得到自然数n以内的全部素数,必须把不大于sqrt(n)的所有素数的倍数剔除,剩下的都是素数。时间复杂度只有O(nloglogn),非常接近O(n)。方法:最小的素数是2,先用2去筛,即把2留下,把2的倍数剔除掉;再用下一个质数,也就是3筛,把3留下,把3的倍数剔除掉;接下去用下一个质数5筛,把5留下,把5的倍数剔除掉;不断重复下去......最后剩下的一定是素数,根据定义,下面给出埃氏筛的两种写法:一种是直接判定素数,另一种是边判定素数边保存素数,代码如下:
1 #include<bits/stdc++.h> 2 using namespace std; 3 const int maxn=1000; 4 bool isp[maxn];int cnt=0,prime[maxn]; 5 void sieve1(){//1、直接判定素数 6 memset(isp,true,sizeof(isp)); 7 isp[0]=isp[1]=false; 8 for(int i=2;i*i<maxn;++i){ 9 if(isp[i]){ 10 for(int j=i*i;j<maxn;j+=i) 11 isp[j]=false; 12 } 13 } 14 } 15 void sieve2(){//2、边判定素数边保存素数 16 memset(isp,true,sizeof(isp)); 17 memset(prime,0,sizeof(prime)); 18 isp[0]=isp[1]=false; 19 for(int i=2;i<maxn;++i){ 20 if(isp[i]){//如果isp[i]==true,则i一定是素数 21 prime[cnt++]=i;//保存素数 22 for(int j=i*i;j<maxn;j+=i) 23 isp[j]=false; 24 } 25 } 26 } 27 int main(){ 28 sieve1();//测试代码 29 for(int i=1;i<maxn;++i) 30 if(isp[i])cout<<i<<endl; 31 /*sieve2(); 32 for(int i=0;i<cnt;++i) 33 cout<<prime[i]<<endl;*/ 34 return 0; 35 }
疑难点一:根据埃氏筛的定义,枚举不大于sqrt(n)的所有素数,将其倍数剔除掉,最终留下的都是素数,为什么只需枚举到sqrt(n)呢?其实原因就是
标签:大于 正整数 max 两种 name nlog turn 除了 span
原文地址:https://www.cnblogs.com/acgoto/p/9488304.html