关于素数筛选,ACM中常用的有两种方法:埃拉托色尼(Eratosthenes)筛法( 复杂度为O( nloglogn ) )和快速筛选法(也叫线性筛法,复杂度为O(n))。
先说第一种筛法:
//埃拉托色尼(Eratosthenes)筛选法:
#define N 10000
bool prime[N]; //纪录N以内的素数
int p[N]; //p[i]是第i个素数
int k=0; //纪录素数的个数
void isprime()
{
long long i,j;
memset(prime,true,sizeof(prime));
for(i=2; i<N; i++)
{
if(prime[i])
{
p[k++]=i;
for(j=i*i; j<N; j+=i)
prime[j]=false;
}
}
}
这种筛法在n为10^6甚至更大的时候可以快速求出1到n之间的所有素数,把之前找出的素数的倍数标记为合数,没被标记的自然为素数,时间复杂度为O(nloglogn),这种方法在解决一般的素数问题中足以。
但不得不说另一种时间复杂度为O(n)的快速筛选法:
//线性筛法:
bool isPrime[N];
int prime[N];
int total;
void makePrime()
{
memset(isPrime,true,sizeof(isPrime));
memset(prime,0,sizeof(prime));
for(int i=2; i<=N; i++)
{
if(isPrime[i]) prime[total++]=i;
for(int j=0; j<total && i*prime[j]<=N; j++)
{
isPrime[i*prime[j]]=false;
if(i%prime[j]==0) break;
}
}
}
它与埃拉托色尼筛法类似,但它保证使任何一个合数,只被它的最小质因数标记过一次,所以整个算法是线性的。但就实际问题而言,两者在运算速度上没有太大差别,大家可大致了解一下。
下面我们来看一下 HDU2710:筛选出1到n之间的所有数的最大最大质因数:
题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2710
实现代码如下:
#include <cstdio>
#include <iostream>
using namespace std;
const int maxn=20005;
int max_factor[maxn]= {0,1};
void init()
{
for(int i=2; i<=maxn; i++)
{
if(!max_factor[i])
for(int j=i; j<=maxn; j+=i)
max_factor[j]=i;
}
}
int main()
{
init();
int n,num,ans;
while(scanf("%d",&n)!=-1)
{
int ans_f=0;
for(int i=0; i<n; i++)
{
scanf("%d",&num);
if(ans_f<max_factor[num])
{
ans_f=max_factor[num];
ans=num;
}
}
printf("%d\n",ans);
//printf("ans_f=%d\n",ans_f);
}
return 0;
}