【ACM算法】-- 数学问题篇 - 素数筛法

第一题: 单个素数判定
在这里插入图片描述
思路:

  1. 素数定义:素数又称质数,指只能被 1 和其 自身 整除的大于1的正整数。注意:1 不是素数 , 2 是素数
  2. 传统思路:因为素数只能表示为 1 * a (a 为其本身)这种因式表达形式,所以需要遍历,从1(不包括 1)开始到 a - 1 的所有正整数,如若存在 n * m = a 则,a不是素数。
  3. 较好的思路:因为素数的判断方法,为从 [ 2 , a-1 ] 逐个判断是否存在 n * m = a 这种因式,所以,我们只需要判断从 [ 2 , sqrt(a) ] 之间的数即可,因为若存在一个因式 n * m = a 这种因式,当 m >sqrt(a) 时,n 必然小于 sqrt(a),如果 n > sqrt(a) 则 n * m > a 。所以就不需要考察 ( sqrt(a) , a-1 ] 这之间的数了,因为当考查他们的时候,其实他们在之前另一个因数的时候就已经考察过了,再次考察,只会浪费时间。

代码如下:

#include<stdio.h>
#include<math.h>
bool judge(int a){
	if(a<=1)return false;
	int bound=(int)sqrt(a)+1;//计算枚举上届,为防止double值带来的精度损失。
	//所以采取根号值取整后+1的方法,所以宁愿多枚举一个也不能少枚举一个。
	for(int i=2;i<bound;i++){//此时就不用等号了,因为bound 一定大于sqrt(a)
		if(a%i==0)return false;
	}
	return true;
}

int main(){
	int a; 
	while(scanf("%d",&a)!=EOF){
		printf(judge(a)==true?"YES\n":"NO\n");
	} 
	return 0;
}

注意: 这里有一个小技巧,就是int bound=(int)sqrt(a)+1;因为sqrt()函数为比较耗时的函数之一,如果将sqrt()函数写进循环里,则每一次循环都要执行一次sqrt()函数,如果写在外面,则只需要执行一次。

第二题: 区间素数判定
在这里插入图片描述
思路: 这里有一句非常重要的一句话:若一个数不是素数,则必存在一个素数为其因数。 这句话是素数筛法的核心,即如果已经判断了一个数为素数,则是其的倍数的数均不是素数。换而言之,如果当前所判断的数,不存在小于它的任何素数为其因数,则其为素数。

代码如下:

#include<stdio.h>
int prime[10000];
int primeSize;
bool mark[10001];
void init(){//这个函数是核心代码,相当于预处理,提高时间效率
	for(int i=1;i<=10000;i++){
		mark[i]=false;
	}//初始化,将所有标记数组置为false 
	primeSize=0;
	for(int i=2;i<=10000;i++){
		if(mark[i]==true)continue;//被标记过了,说明不是素数 
		prime[primeSize++]=i;
		for(int j=i*i;j<=10000;j+=i){
			mark[j]=true;
		}
	}
}
int main(){
	init();
	int n;
	while(scanf("%d",&n)!=EOF){//输入n,然后进行格式调整
		bool isOutput=false;
		for(int i=0;i<primeSize;i++){
			if(prime[i]<n&&prime[i]%10==1){
				if(!isOutput){
					isOutput=true;
					printf("%d",prime[i]);
				}
				else{
					printf(" %d",prime[i]);
				}
			}
		}
		if(isOutput==false){
			printf("-1\n");
		}else{
			printf("\n");
		}
	}
	return 0;
}

注意:
此处有一个难点:
就是为什么当确定一个数为素数的时候,在标记其倍数的时候是从i * i 开始的,而不考虑 ( i-1) * i ,首先,需要明确,我们写这个循环是为了标记某一个数是否为非素数,目的是为了标记,当对于某一个非素数 m 其因式分解为 i * k (k < i),因为我们的目的是为了标记,所以当 i 这个游标为 k 时,就已经把 m 给标记了,所以我们只需要从 i * i 开始即可。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值