素数判断入门201808

素数的定义:一个正整数只能被1和自己整除。

关键字:正整数、只有2个因子。

----------------------------------------------------------------------------------------------------------------------------------------------------------------

知识点罗列:

入门题:判断一个数字是否是素数:

当判断一个数字是素数与否的时候,用适量的数学思维,可以大大减少枚举的次数。以下三个方法是层次递进地减少枚举的量。

1、暴力枚举:O(n)

2、折半枚举:O(n/2)

3、开方枚举:O(n)

简单题:判断一堆数字是否是素数:

当判断的量上升,也就是同一个操作要执行多次,则需要再用数学思维进行优化,可以枚举的次数再降为。

4、开方枚举(函数版):O(n*n

5、线性筛选:O(n)

----------------------------------------------------------------------------------------------------------------------------------------------------------------

详解:

1、暴力枚举O(n):从2->(x-1)枚举判断,是否有因子。


//判断素数1:暴力枚举
//时间复杂度:O(n) 

#include<cstdio>

int main()
{
	int x;
	scanf("%d",&x);
	if(x>1)//素数一定大于 1(性质) 
	{
		for(int i=2;i<x;i++)
		{
			if(x%i==0) 
			{
				printf("0");//有因子,非素数
				return 0; 
			}
		}
	}
	printf("1");
	return 0; 
}

 

2、折半枚举O(n/2):

思维的优化:

    例如:一个数字是48,能被2整除,就是2*24=48。

    所以:只要找到2,就会找到对应的24

    只要枚举前面一半的数字,就等于同时枚举了另外一半


//判断素数2:简单优化砍一半 
//时间复杂度:O(n/2) 

#include<cstdio>

int main()
{
	int x,y;
	scanf("%d",&x);
	y=x/2;//y是x的一半 
	if(x>1)
	{
		for(int i=2;i<y;i++)//枚举的次数只有原来的一半 
		{
			if(x%i==0) 
			{
				printf("0");//有因子,非素数
				return 0; 
			}
		}
	}
	printf("1");
	return 0; 
}

3、开方枚举:O(n)

思维的再优化:

    例如:一个数字是48,能被2整除,就是2*24=48。

    如果将48的因子分成2堆:2属于左边堆,24属于右边堆。那么这两堆因子的交汇点会在哪里呢?

    答案是:开根号的地方。

    所以:只要枚举到这个数字的开根号,就等于同时枚举了另外一半的因子


//判断素数3:继续优化:降维 
//时间复杂度:O(√n) 

#include<cstdio>
#include<cmath>//sqrt开根函数要用 
int main()
{
	int x,y;
	scanf("%d",&x);
	y=sqrt(x+1);//y表示x的开根因子的取整,+1是保险 
	if(x>1)
	{
		for(int i=2;i<=y;i++)//枚举的次数只有原来的开根号次 
		{
			if(x%i==0) 
			{
				printf("0");//有因子,非素数
				return 0; 
			}
		}
	}
	printf("1");
	return 0; 
}

 

题目升级:求1-n的所有素数

4、开方枚举(函数版):O(n*n


//求1-n的素数:函数版 
//时间复杂度:O(n√n) 

#include<cstdio>
#include<cmath>//sqrt开根函数要用 

int pd(int x)//当前判断的数字是x 
{
	if(x<2) return 0;//小于2,非素数
	int t=sqrt(x+1);
	for(int i=2;i<=t;i++)
	{
		if(x%i==0) return 0;//有因子的话,非素数 
	} 
	return 1;//是素数 
}
int main()
{
	int n;
	scanf("%d",&n);
	for(int i=2;i<=n;i++)
	{
		if(pd(i)==1)//如果函数返回值是1,就是素数 
		{
			printf("%d ",i);
		}
	}
	return 0; 
}

5、线性筛选:O(n)

    当n的值很大的时候,对于每个n枚举因子,还是很大的运算量。

    所以需要用到一个打表的思维,用数组f[i]来表示i是否素数:

    1、设全部的数字都是素数;

    2、小的奇数应该是素数;

    3、素数的倍数一定不是素数,剔除;

//求1-n的素数:线性筛选 
//时间复杂度:O(n) 
#include<cstdio>
#include<cstring>//memset函数用
 
int f[100005];//10W以内的素数表 

int main()
{
	int n=100000;
	memset(f,0,sizeof(f));//将f数组初始化为0:素数 
	f[1]=1;//1不是素数
	 
	for(int i=2;i<=n;i++)
	{
		if(f[i]==0)//i是素数, 
		{
			for(int j=i*2;j<=n;j+=i)
			{
				f[j]=1;//i的倍数都不是素数
			}
		}
	}
	//以上是打表部分 
	
	scanf("%d",&n);
	
	for(int i=1;i<=n;i++)//直接查表,完美! 
	{
		if(f[i]==0) printf("%d ",i); 
	}
	 
	return 0;
}

   到这里,素数的入门介绍就差不多了。如果有兴趣了解更多数论知识的同学,

请移步到   NOIP学习大纲整理  里面有2个章节,从入门开始讲数论。加油o~

 

 

 

 

 

 

 

 

 

 

 

 

 

 

猜你喜欢

转载自blog.csdn.net/liusu201601/article/details/81477001