素数筛选

今天做素数筛选的时候突然有了一个想法,就是比如题目让你求前n个连续的素数,素数的取值范围已给,当你去开一个数组时,不确定最后一个素数是多大,这是你无法准确的知道该开多大的数组,开多了浪费空间,这时候你可以先用你已经写好的程序去算一下当求到最后一个素数,该素数是多大,那么你再定义这个数组的时候就可以开比这个素数稍大一点的就行了


第一种:剔除2 3 4 5 6 ... ... 的倍数

在i从2开始的增一变化过程中,剔除i的倍数即j*i(j是大于等于2的自然数,j的上限是问题规模M)
为了减少重复步骤,可以每当i递增到等于第一个没有被剔除的(素)数时再剔除该数的倍数,
重复上述过程至i到达问题规模m的平方根+1

需要说明的三个问题:
假设循环到第n个数,如果该数没有被剔除,那么该数不能是前边所有数的倍数,该数更不可能是后边数的倍数,该

数就是素数。
如果该数是合数却没被剔除,那么该数能分解为两个小于该数的数的积的形式,而前边剔除的数包含了所有小于该

数的数之间的积,这是矛盾的。

为什么筛选循环的第一层只循环至问题规模m的平方根+1
因为,对于一个数m,所有大于该数平方根的数的积已经大于该数了,再剔除下去只是多余。

为什么筛选循环的第二层只循环至MAX/i?
因为此时j*MAX/i就等于MAX,此时需要标记为错误的数已经到了问题的规模即MAX,没有必要在标记比MAX大的值不

是素数,此外用来标记i*j不是素数的数组只有MAX+1的容量,这样做是向不是自己申请的内存空间里写数据,是危

险的。

MAX是要求的范围,比如1000000以内的数
    int t=0,m=sqrt(MAX)+1;
    for(int i=2;i<m;i++)
        for(int j=2;i*j<=MAX;j++)
            book[i*j]=1;


判断一个数是不是素数的高效算法:当素数大于等于5时,素数一定存在于6的倍数的两边,比如5和7在6的两边,11和13在12的两边,但是6的倍数的两边的数不一定是素数

bool is_prime(int num)//判断是不是素数
{
    if(num==2 || num==3)
        return true;
    if(num%6!=1 && num%6!=5)
        return false;
    for(int i=5;i*i<=num;i+=6)
    {
        if(num%i==0 || num%(i+2)==0)
            return false;
    }
    return true;
}


bool Prime()//素数筛选,MAX依然是要求解的范围
{
    book[2]=book[3]=1;
    for(int i=6;i<=MAX;i+=6)//只对6的倍数的两边的数进行筛选
    {
        if(is_prime(i-1))//对6的倍数两边的数进行筛选
            book[i-1]=1;
        if(is_prime(i+1))
            book[i+1]=1;
    }
}


评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值