素数筛选法

这里将介绍4中方法筛选素数,并统一输出运行时间进行比较,统一用标记法,统一筛选10000005内的素数

一、暴力

也就是最原始的方法,从2遍历到sqrt(n)如果有一个数能被n整除,就不是素数,结果输出4.887秒,太耗时

#include<bits/stdc++.h>
#include<time.h>
#define maxn 10000005
using namespace std;
bool prime[maxn];
void Screening()
{
	prime[0]=prime[1]=0;
	for(int i=2;i<maxn;i++)
	{
		bool flag=0;
		int lim=(int)sqrt((double)i)+0.5;
		for(int j=2;j<lim;j++)
		if(i%j==0)
		{
			flag=1;
			break;
		}
		
		if(flag==0) prime[i]=1;
	}
}
int main()
{
   clock_t start,finish;
   double totaltime;
   start=clock();//开始计时 
   
    Screening();
             
   finish=clock();//结束 
	
   totaltime=(double)(finish-start)/CLOCKS_PER_SEC;//计算 
   cout<<totaltime<<"秒!"<<endl;//4.887秒!
   return 0;
}

二、普通筛选法

先将偶数标记,对于奇数,筛去所有倍数,运行时间为0.321秒!

#include<bits/stdc++.h>
#include<time.h>
#define maxn 10000000005
using namespace std;
bool prime[maxn]; //如果是0,就是是素数 
void Screening()
{
	int lim=(int)sqrt((double)maxn+0.5);
	for(int i=4;i<=maxn;i+=2) prime[i]=1;
	
	for(int j=3;j<lim;j+=2)
	for(int k=j+j;k<=maxn;k+=j) prime[k]=1;
}
int main()
{
   clock_t start,finish;
   double totaltime;
   start=clock();//开始计时 
   
    Screening();
	             
   finish=clock();//结束 

   totaltime=(double)(finish-start)/CLOCKS_PER_SEC;//计算 
   cout<<totaltime<<"秒!"<<endl;//0.321秒!
   
   return 0;
}

 

三、埃拉托色尼(Eratosthenes)筛法

筛去所有素数的倍数,运行时间为0.123秒!

#include<bits/stdc++.h>
#include<time.h>
#define maxn 10000005
using namespace std;
bool prime[maxn]; //如果是0,就是是素数 
void Screening()
{
	int lim=(int)sqrt((double)maxn+0.5);
	for(int i=2;i<lim;i++)
	if(!prime[i])
	for(int j=i*i;j<maxn;j+=i)
	prime[j]=1;
}
int main()
{
   clock_t start,finish;
   double totaltime;
   start=clock();//开始计时 
   
    Screening();
	             
   finish=clock();//结束 

   totaltime=(double)(finish-start)/CLOCKS_PER_SEC;//计算 
   cout<<totaltime<<"秒!"<<endl;//0.123秒!
   
   return 0;
}

 

四、线性筛(欧拉法)

首先,根据欧拉公式,任何合数(非素数)都能表示成一系列素数的积。 上面的筛选法中,有些数会被重复标记很多次,比如12,会被2,3,4,6的倍数标记,欧拉筛就避免了这种情况。
利用了每个合数必有一个最小素因子,每个合数仅被它的最小素因子筛去正好一次。所以为线性时间。 
代码中体现在:  if(i%prime[j]==0)break; 
prime数组 中的素数是递增的,当 i 能整除 prime[j],那么 i*prime[j+1] 这个合数肯定被 prime[j] 乘以某个数筛掉。 
因为i中含有prime[j], prime[j] 比 prime[j+1] 小。接下去的素数同理。所以不用筛下去了。 
在满足i%prme[j]==0这个条件之前以及第一次满足改条件时,prime[j]必定是prime[j]*i的最小因子。 

#include<bits/stdc++.h>
#define M 10000005
using namespace std;
int prime[M];
bool vis[M];
void screening()
{
	vis[0]=vis[1]=true;
	int cnt=0;
	for(int i=2;i<M;i++)
	{
		if(!vis[i]) prime[cnt++]=i;
		
		for(int j=0;j<cnt&&i*prime[j]<M;j++)
		{
			vis[i*prime[j]]=true;
			if(i%prime[j]==0) break;
		}
	}
}
int main()
{
	screening();
	int n,m;
	cin>>n>>m;
	while(m--)
	{
		int x;
		cin>>x;
		if(vis[x])	
			cout<<"No"<<endl;
		else
			cout<<"Yes"<<endl;
	}
	return 0;
} 

 

数据量大时候会很快

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值