【算法学习】素数筛和线性筛问题

1.原理分析(素数筛和线性筛)

在这里插入图片描述在这里插入图片描述

2.关于素数问题

a.标记0-500里面的素数

代码如下:

#include<stdio.h>
#define max_n 500

int arr[max_n + 5] = {1, 1};
void prime(){
    for(int i = 2; i * i <= max_n; i++){
        if(arr[i]) continue;//对偶逻辑减少缩进
        for(int j = i * i; j < max_n; j += i){//从i * i开始  i * (i - 1)已经被(i-1)或其素因子标记过了
            arr[j] = 1;
        }
    }
}

int main(){
    int n;
    prime();
    while(~scanf("%d", &n)){
        if(arr[n]) printf("%d is not prime\n", n);
        else printf("%d is prime\n", n);
    }
    return 0;

}

运行结果
在这里插入图片描述

b.欧拉7题

题目描述

第10001个素数
列出前6个素数,它们分别是2、3、5、7、11和13。我们可以看出,第6个素数是13。
第10,001个素数是多少?

1)基础版代码(普通素数方法)

#include<stdio.h>
int is_val(int n){
    for(int i = 2; i * i <= n; i++){
        if(n % i == 0) return 0;
    }
    return 1;
}
int main(){
    int i, cnt;
    for(i = 2, cnt = 0; cnt < 10001; i++){
        if(is_val(i)) cnt += 1;
    }
    printf("%d\n", i - 1);
    return 0;
}

2)进阶版代码(素数筛方法)

#include<stdio.h>
#include<inttypes.h>
#define max_n 200000//素数符合一个规则 即要找第n个素数 这个素数一定在20*n的范围中

int arr[max_n + 5] = {0};

void prime(){
    for(int64_t i = 2; i <= max_n; i++){//i的上限为max_n而不是sqrt(max_n),如果用后者,则所有的素数全部找出了,但是并没有将第100往后的素数遍历到,也就是100以后的素数未存入数组的对应位置
        if(arr[i]) continue;//当继续往下执行时,则说明i是素数
        //arr[++arr[0]] = i;
        ++arr[0];
        arr[arr[0]] = i;//arr[0]记录素数个数,将第i个素数赋值给arr[i],因为当循环到i时,前i个数已经判断完毕,所以可以使用arr[i]
        for(int64_t j = i * i; j <= max_n; j += i){//j = i * i i最大为200000,所以j需用64位,如果i用int,则在运算时200000*200000时就会爆掉
            arr[j] = 1;
        }
    }
}

int main(){
    prime();
    printf("%d is the 10001st prime number\n", arr[10001]);
    return 0;
}

在这里插入图片描述

3)进进阶版代码(线性筛方法)

#include<stdio.h>
#define max_n 200000

int prime[max_n + 5] = {0};

void init(){
    for(int i = 2; i < max_n; i++){//i的上界为max_n/2时,素数全部标记,但没更新到对应的数组中
        if(!prime[i]) prime[++prime[0]] = i;//如果是素数,则更新素数表
        for(int j = 1; j <= prime[0]; j++){//j不能从0开始 prime[0]存放的素数个数
            if(i * prime[j] > max_n) break;
            prime[i * prime[j]] = 1;
            if(i % prime[j] == 0) break;//当此时的i对素数表中的素数取模为0时停止标记
        }
    }
}

int main(){

    init();
    printf("%d is the 10001st prime number\n", prime[10001]);
    
    return 0;
}


在这里插入图片描述

3.扩展问题

记住素数筛和线性筛是一类框架,不仅仅是算法,可以用其解决相似的问题

a.快速写出2-10000每个数对应的最小素因子

#include<stdio.h>
#define max_n 10000

int arr[max_n + 5] = {0};

void prime(){
    for(int i = 2; i <= max_n; i++){//i的上界为max_n,如果是sqrt,则当i>100时,素数对应的数组里面是0
        if(arr[i]) continue;
        for(int j = i; j <= max_n; j += i){//j从i开始,如果j从i*i开始,则遍历不到当前的素数i,此时对应的arr[i]=0
            if(arr[j]) continue;//如果已经用素数标记过,则不再更新值,前面的素数肯定更小
            arr[j] = i;
        }
    }
    return ;
}

int main(){
    prime();
    int n;
    while(~scanf("%d", &n)){
        printf("min prime yinzi is %d\n", arr[n]);
    }
    return 0;
}

在这里插入图片描述

b.快速写出2-10000每个数对应的最大素因子

#include<stdio.h>
#define max_n 10000

int arr[max_n + 5] = {0};

void prime(){
    for(int i = 2; i <= max_n; i++){//i的上界为max_n,如果是sqrt,则当i>100时,素数对应的数组里面是0
        if(arr[i]) continue;
        for(int j = i; j <= max_n; j += i){//j从i开始,如果j从i*i开始,则遍历不到当前的素数i,此时对应的arr[i]=0
            //if(arr[j]) continue;//如果已经用素数标记过,则不再更新值,前面的素数肯定更小
            arr[j] = i;
        }
    }
    return ;
}

int main(){
    prime();
    int n;
    while(~scanf("%d", &n)){
        printf("min prime yinzi is %d\n", arr[n]);
    }
    return 0;
}

在这里插入图片描述

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

沙diao网友

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值