牛客网刷题 | BC127 筛选法求素数

😁博客主页😁:🚀从0至1-优快云博客🚀
🤑博客内容🤑:🍭C语言、C++、数据结构、嵌入式、Linux🍭
😎本文内容🤣:🍭BC127 筛选法求素数🍭
😎金句分享😎:🍭No🍭

目录

描述

输入描述:

输出描述:

示例1

首先要理解题目意思

示例

解释示例

输入 10

输入 15

关键点总结

解题思路 

步骤详解

代码 

代码解释

详细步骤解释

示例

扩展

拓展1:多组输入处理

拓展2:优化筛选法

拓展3:统计不同范围内的素数

拓展4:输出最大素数和最小素数


描述

用筛选法求n以内的素数。筛选法求解过程为:将2~n之间的正整数放在数组内存储,将数组中2之后的所有能被2整除的数清0,再将3之后的所有能被3整除的数清0 ,以此类推,直到n为止。数组中不为0 的数即为素数。

输入描述:

多组输入,每行输入一个正整数(不大于100)。

输出描述:

针对每行输入的整数n,输出两行,第一行,输出n之内(包括n)的素数,用空格分隔,

第二行,输出数组中2之后被清0 的个数。每行输出后换行。

示例1


首先要理解题目意思

任务:使用筛选法(也称为埃拉托斯特尼筛法)找出给定范围内的所有素数。

筛选法过程

  1. 初始化数组:将2到n之间的所有正整数存储在一个数组中。
  2. 标记非素数
    • 从2开始,将数组中2之后的所有能被2整除的数标记为0。
    • 然后从3开始,将数组中3之后的所有能被3整除的数标记为0。
    • 依次类推,直到处理完所有小于等于n的数。
  3. 结果:数组中不为0的数即为素数。

输入描述

  • 多组输入,每行输入一个正整数(不大于100)。

输出描述

  • 对于每行输入的整数n,输出两行:
    • 第一行:输出n之内(包括n)的所有素数,用空格分隔。
    • 第二行:输出数组中2之后被清0的个数。

示例

假设输入如下:

10
15

预期输出

2 3 5 7 
6
2 3 5 7 11 13 
8

解释示例

输入 10
  1. 初始化数组

    • 数组 arr 初始化为:{0, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10}
  2. 筛选过程

    • 当 p = 2 时:
      • 标记 46810 为0。
      • 数组变为:{0, 0, 2, 3, 0, 5, 0, 7, 0, 9, 0}
    • 当 p = 3 时:
      • 标记 9 为0。
      • 数组变为:{0, 0, 2, 3, 0, 5, 0, 7, 0, 0, 0}
  3. 输出结果

    • 素数:2 3 5 7
    • 被清0的个数:6
输入 15
  1. 初始化数组

    • 数组 arr 初始化为:{0, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}
  2. 筛选过程

    • 当 p = 2 时:
      • 标记 468101214 为0。
      • 数组变为:{0, 0, 2, 3, 0, 5, 0, 7, 0, 9, 0, 11, 0, 13, 0, 15}
    • 当 p = 3 时:
      • 标记 915 为0。
      • 数组变为:{0, 0, 2, 3, 0, 5, 0, 7, 0, 0, 0, 11, 0, 13, 0, 0}
    • 当 p = 5 时:
      • 标记 10 已经是0,不需要再次标记。
      • 数组保持不变:{0, 0, 2, 3, 0, 5, 0, 7, 0, 0, 0, 11, 0, 13, 0, 0}
  3. 输出结果

    • 素数:2 3 5 7 11 13
    • 被清0的个数:8

关键点总结

  1. 初始化数组:将2到n之间的所有正整数存储在数组中。
  2. 标记非素数:逐步将每个素数的倍数标记为0。
  3. 输出结果
    • 输出数组中不为0的数(即素数)。
    • 统计并输出在2之后被清0的数的个数。

解题思路 

  1. 输入处理

    • 读取一个正整数 n(不大于100)。
  2. 初始化数组

    • 创建一个大小为100的数组 arr,并将所有元素初始化为0。
    • 将数组索引从2到 n 的位置分别赋值为相应的整数。
  3. 筛选过程

    • 使用双重循环来标记非素数:
      • 外层循环从2开始遍历到 n,每次迭代时 j 表示当前正在检查的数。
      • 内层循环从 j+1 开始遍历到 n,每次迭代时 i 表示当前要检查的数。
      • 如果 arr[i] 能被 j 整除,则将 arr[i] 置为0,表示 arr[i] 不是素数。
  4. 统计和输出结果

    • 遍历数组,输出所有不为0的数(即素数),并用空格分隔。
    • 统计并输出在2之后被清0的数的个数。

步骤详解

  1. 输入处理

    • 使用 scanf 函数从标准输入读取一个整数,并存储在变量 n 中。
  2. 初始化数组

    • 创建一个大小为100的整数数组 arr,并将所有元素初始化为0。
    • 使用 for 循环将数组 arr 的索引从2到 n 的位置分别赋值为相应的整数。
  3. 筛选过程

    • 使用外层循环从2开始遍历到 n,每次迭代时 j 表示当前正在检查的数。
    • 使用内层循环从 j+1 开始遍历到 n,每次迭代时 i 表示当前要检查的数。
    • 如果 arr[i] 能被 j 整除(即 arr[i] % j == 0),则将 arr[i] 置为0,并增加计数器 j
  4. 输出结果

    • 使用 for 循环遍历数组,输出所有不为0的数(即素数),并用空格分隔。
    • 输出在2之后被清0的数的个数。

代码 

#include <stdio.h>
int main()
{
    int n, i, j;
    int arr[100] = {0};  // 设初始数组元素为100个0
    scanf("%d", &n);     // 读取输入的整数n
    
    // 初始化数组,将数组索引从2到n的位置分别赋值为相应的整数
    for (i = 2; i <= n; i++)   
        arr[i] = i;     // 为了方便,设数组下标和数组元素一样,从2到n
    
    // 筛选过程
    for (j = 2; j <= n; j++)   // 外循环为2到n,即被2到n的数整除
    {
        for (i = j + 1; i <= n; i++)   // 内循环为遍历数组进行比较,每趟循环的数组下标从j+1开始
        { 
            if (arr[i] % j == 0)    // 若能被j(从2到n)整除
                arr[i] = 0;          // 还原为0
        }
    }
    
    // 遍历数组,输出未被清0的数(即素数)
    for (i = 2, j = 0; i <= n; i++)    // 遍历数组,
    {
        if (arr[i] != 0)
            printf("%d ", arr[i]);   // 未被清0的数打印出来
        else 
            j++;   // 清0的数,计数+1
    }
    printf("\n");   // 换行
    
    // 打印被清0的数的个数
    printf("%d", j);   // 打印被清0的数的个数
    
    return 0;
}

代码解释

#include <stdio.h>
int main()
{
    int n, i, j;
    int arr[100] = {0};  // 设初始数组元素为100个0
    scanf("%d", &n);     // 读取输入的整数n
    
    // 初始化数组,将数组索引从2到n的位置分别赋值为相应的整数
    for (i = 2; i <= n; i++)   
        arr[i] = i;     // 为了方便,设数组下标和数组元素一样,从2到n
    
    // 筛选过程
    for (j = 2; j <= n; j++)   // 外循环为2到n,即被2到n的数整除
    {
        for (i = j + 1; i <= n; i++)   // 内循环为遍历数组进行比较,每趟循环的数组下标从j+1开始
        { 
            if (arr[i] % j == 0)    // 若能被j(从2到n)整除
                arr[i] = 0;          // 还原为0
        }
    }
    
    // 遍历数组,输出未被清0的数(即素数)
    for (i = 2, j = 0; i <= n; i++)    // 遍历数组,
    {
        if (arr[i] != 0)
            printf("%d ", arr[i]);   // 未被清0的数打印出来
        else 
            j++;   // 清0的数,计数+1
    }
    printf("\n");   // 换行
    
    // 打印被清0的数的个数
    printf("%d", j);   // 打印被清0的数的个数
    
    return 0;
}

详细步骤解释

  1. 输入处理

    scanf("%d", &n);
    • 使用 scanf 函数从标准输入读取一个整数 n
  2. 初始化数组

    for (i = 2; i <= n; i++)
        arr[i] = i;
    • 使用 for 循环将数组 arr 的索引从2到 n 的位置分别赋值为相应的整数。
    • 例如,如果 n 是5,则数组 arr 的前几个元素会被设置为:arr[2] = 2arr[3] = 3arr[4] = 4arr[5] = 5
  3. 筛选过程

    for (j = 2; j <= n; j++)   // 外循环为2到n,即被2到n的数整除
    {
        for (i = j + 1; i <= n; i++)   // 内循环为遍历数组进行比较,每趟循环的数组下标从j+1开始
        { 
            if (arr[i] % j == 0)    // 若能被j(从2到n)整除
                arr[i] = 0;          // 还原为0
        }
    }
    • 外层循环 (for (j = 2; j <= n; j++)):
      • 从2开始遍历到 n,每次迭代时 j 表示当前正在检查的数。
    • 内层循环 (for (i = j + 1; i <= n; i++)):
      • 从 j+1 开始遍历到 n,每次迭代时 i 表示当前要检查的数。
      • 如果 arr[i] 能被 j 整除(即 arr[i] % j == 0),则将 arr[i] 置为0,表示 arr[i] 不是素数。
  4. 输出结果

    for (i = 2, j = 0; i <= n; i++)    // 遍历数组,
    {
        if (arr[i] != 0)
            printf("%d ", arr[i]);   // 未被清0的数打印出来
        else 
            j++;   // 清0的数,计数+1
    }
    printf("\n");   // 换行
    printf("%d", j);   // 打印被清0的数的个数
    • 初始化计数器 (j = 0):
      • 使用 j 计数被清0的数的个数。
    • 遍历数组 (for (i = 2, j = 0; i <= n; i++)):
      • 从2开始遍历到 n,每次迭代时 i 表示当前检查的数。
      • 如果 arr[i] 不为0,则打印该数(即素数)。
      • 如果 arr[i] 为0,则增加计数器 j,表示有一个数被清0。
    • 换行 (printf("\n")):
      • 在输出完素数后换行。
    • 输出被清0的数的个数 (printf("%d", j)):
      • 打印在2之后被清0的数的个数。

示例

假设输入的 n 是10,那么这段代码的工作过程如下:

  1. 初始化数组

    for (i = 2; i <= n; i++)
        arr[i] = i;
    • 数组 arr 初始化为:{0, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10}
  2. 筛选过程

    • j = 2 时:

      for (i = 3; i <= 10; i++)
      {
          if (arr[i] % 2 == 0)
              arr[i] = 0;
      }
      • 标记46810为0。
      • 数组变为:{0, 0, 2, 3, 0, 5, 0, 7, 0, 9, 0}
    • j = 3 时:

      for (i = 4; i <= 10; i++)
      {
          if (arr[i] % 3 == 0)
              arr[i] = 0;
      }
      • 标记9为0。
      • 数组变为:{0, 0, 2, 3, 0, 5, 0, 7, 0, 0, 0}
    • j = 4j = 10 时:

      • 没有新的数被标记为0,因为之前已经被标记过的数不会再被标记。
  3. 输出结果

    • 素数:2 3 5 7
    • 被清0的个数:6

扩展

拓展1:多组输入处理

需求

  • 处理多组输入,每行输入一个正整数(不大于100),并针对每组输入输出相应的结果。

示例

输入:
10
15

输出:
2 3 5 7 
6
2 3 5 7 11 13 
8

实现

  • 使用 while 循环不断读取输入,直到遇到文件结束符(EOF)。

多组输入处理的筛选法求n以内的素数

#include <stdio.h>

int main() {
    int n, i, j;
    int arr[100] = {0};  // 设初始数组元素为100个0
    
    // 使用 while 循环不断读取输入,直到遇到文件结束符(EOF)
    while (scanf("%d", &n) != EOF && n > 0) {
        if (n > 100) {
            printf("Input should be less than or equal to 100.\n");
            continue;
        }
        
        // 初始化数组,将数组索引从2到n的位置分别赋值为相应的整数
        for (i = 2; i <= n; i++)
            arr[i] = i;
        
        // 筛选过程
        for (j = 2; j * j <= n; j++) {   // 外循环为2到sqrt(n),即被2到sqrt(n)的数整除
            if (arr[j] != 0) {           // 如果arr[j]不为0,说明j是素数
                for (i = j * j; i <= n; i += j) { // 内循环为遍历数组进行比较,每趟循环的数组下标从j*j开始
                    if (arr[i] != 0) {     // 若能被j整除
                        arr[i] = 0;          // 还原为0
                    }
                }
            }
        }
        
        // 统计被清0的数的个数
        int count_cleared = 0;
        for (i = 2; i <= n; i++) {
            if (arr[i] == 0)
                count_cleared++;
        }
        
        // 输出素数
        for (i = 2; i <= n; i++) {
            if (arr[i] != 0)
                printf("%d ", arr[i]);   // 未被清0的数打印出来
        }
        printf("\n");
        
        // 打印被清0的数的个数
        printf("%d\n", count_cleared);
    }
    
    return 0;
}



拓展2:优化筛选法

需求

  • 优化筛选法,减少不必要的计算。

实现

  • 只需要检查到 sqrt(n) 即可。
  • 使用布尔数组来标记素数,避免使用整数数组。

#include <stdio.h>
#include <stdbool.h>

void sieveOfEratosthenes(int n) {
    bool is_prime[n + 1];  // 布尔数组,初始化为true,表示所有数都是素数
    for (int i = 0; i <= n; i++) {
        is_prime[i] = true;
    }
    is_prime[0] = is_prime[1] = false; // 0和1不是素数

    int count_cleared = 0;  // 记录被清0的数的个数
    for (int p = 2; p * p <= n; p++) {  // 外循环为2到sqrt(n),即被2到sqrt(n)的数整除
        if (is_prime[p]) {              // 如果p是素数
            for (int j = p * p; j <= n; j += p) {  // 内循环为遍历数组进行比较,每趟循环的数组下标从p*p开始
                if (is_prime[j]) {                 // 若j是素数
                    is_prime[j] = false;             // 标记j为非素数
                    count_cleared++;               // 增加被清0的计数
                }
            }
        }
    }

    // 输出素数
    for (int i = 2; i <= n; i++) {
        if (is_prime[i]) {
            printf("%d ", i);  // 未被清0的数打印出来
        }
    }
    printf("\n");

    // 输出被清0的数的个数
    printf("%d\n", count_cleared);
}

int main() {
    int n;
    while (scanf("%d", &n) != EOF && n > 0) {  // 使用 while 循环不断读取输入,直到遇到文件结束符(EOF)
        if (n > 100) {
            printf("Input should be less than or equal to 100.\n");
            continue;
        }
        sieveOfEratosthenes(n);  // 调用筛选函数
    }
    return 0;
}



拓展3:统计不同范围内的素数

需求

  • 输入多个范围,每个范围由两个整数 a 和 b 表示,输出每个范围内(包括 a 和 b)的所有素数及其个数。

示例

输入:
10 20
25 30

输出:
11 13 17 19 
4
29 
1

实现

  • 读取多个范围 [a, b],并对每个范围应用筛选法。

#include <stdio.h>
#include <stdbool.h>

void sieveInRange(int a, int b) {
    if (b < 2) {
        printf("No prime numbers in range [%d, %d]\n", a, b);
        printf("0\n");
        return;
    }

    bool is_prime[b + 1];  // 布尔数组,初始化为true,表示所有数都是素数
    for (int i = 0; i <= b; i++) {
        is_prime[i] = true;
    }
    is_prime[0] = is_prime[1] = false; // 0和1不是素数

    for (int p = 2; p * p <= b; p++) {  // 外循环为2到sqrt(b),即被2到sqrt(b)的数整除
        if (is_prime[p]) {              // 如果p是素数
            for (int j = p * p; j <= b; j += p) {  // 内循环为遍历数组进行比较,每趟循环的数组下标从p*p开始
                if (is_prime[j]) {                 // 若j是素数
                    is_prime[j] = false;             // 标记j为非素数
                }
            }
        }
    }

    int count_primes = 0;  // 记录素数的个数
    for (int i = a; i <= b; i++) {
        if (is_prime[i]) {
            printf("%d ", i);  // 未被清0的数打印出来
            count_primes++;
        }
    }
    printf("\n");

    // 输出素数的个数
    printf("%d\n", count_primes);
}

int main() {
    int a, b;
    while (scanf("%d %d", &a, &b) != EOF) {  // 使用 while 循环不断读取输入,直到遇到文件结束符(EOF)
        if (a > b || a < 0 || b > 100) {
            printf("Invalid range. Ensure 0 <= a <= b <= 100.\n");
            continue;
        }
        sieveInRange(a, b);  // 调用筛选函数
    }
    return 0;
}



拓展4:输出最大素数和最小素数

需求

  • 对于每个输入的 n,输出 n 以内的最大素数和最小素数。

示例

输入:
10
15

输出:
2 7
2 13

实现

  • 在筛选过程中记录最大和最小的素数。

#include <stdio.h>
#include <stdbool.h>

void sieveAndFindExtremes(int n) {
    if (n < 2) {
        printf("No prime numbers in range [2, %d]\n", n);
        return;
    }

    bool is_prime[n + 1];  // 布尔数组,初始化为true,表示所有数都是素数
    for (int i = 0; i <= n; i++) {
        is_prime[i] = true;
    }
    is_prime[0] = is_prime[1] = false; // 0和1不是素数

    for (int p = 2; p * p <= n; p++) {  // 外循环为2到sqrt(n),即被2到sqrt(n)的数整除
        if (is_prime[p]) {              // 如果p是素数
            for (int j = p * p; j <= n; j += p) {  // 内循环为遍历数组进行比较,每趟循环的数组下标从p*p开始
                if (is_prime[j]) {                 // 若j是素数
                    is_prime[j] = false;             // 标记j为非素数
                }
            }
        }
    }

    int min_prime = -1;  // 记录最小素数
    int max_prime = -1;  // 记录最大素数
    for (int i = 2; i <= n; i++) {
        if (is_prime[i]) {
            if (min_prime == -1) {
                min_prime = i;  // 设置第一个找到的素数为最小素数
            }
            max_prime = i;  // 更新最大素数
        }
    }

    if (min_prime == -1) {
        printf("No prime numbers in range [2, %d]\n", n);
    } else {
        printf("%d %d\n", min_prime, max_prime);  // 输出最小和最大素数
    }
}

int main() {
    int n;
    while (scanf("%d", &n) != EOF && n > 0) {  // 使用 while 循环不断读取输入,直到遇到文件结束符(EOF)
        if (n > 100) {
            printf("Input should be less than or equal to 100.\n");
            continue;
        }
        sieveAndFindExtremes(n);  // 调用筛选函数
    }
    return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值