循环结构,素数和的问题

本关任务:输入n(10≤n≤10000)和k(1≤ k≤10),求n以内最大的k个素数,按降序排列并将和输出在最后。

以下是使用 C 语言实现的代码:

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

bool is_prime(int n) {
    if (n <= 1) {
        return false;
    }
    for (int i = 2; i * i <= n; ++i) {
        if (n % i == 0) {
            return false;
        }
    }
    return true;
}

int main() {
    int n, k, prime_count = 0, sum = 0;
    printf("输入n(10≤n≤10000)和k(1≤k≤10): ");
    scanf("%d %d", &n, &k);

    if (n < 10 || n > 10000 || k < 1 || k > 10) {
        printf("输入的范围不正确。\n");
        return 1;
    }

    for (int i = n; i >= 2 && prime_count < k; --i) {
        if (is_prime(i)) {
            prime_count++;
            sum += i;
            printf("%d", i);
            if (prime_count < k) {
                printf(", ");
            } else {
                printf("\n");
            }
        }
    }

    printf("最大的%d个素数和为: %d\n", k, sum);
    return 0;
}

运行时,按照提示输入 n 和 k 的值,程序将输出 n 以内最大的 k 个素数(降序排列),以及这些素数的和。

题目可以分为两个部分:找到最大的 k 个素数和求它们的和。下面的代码中,首先定义了一个 is_prime 函数,用于判断一个数是否为素数。然后,使用容量为 k 的小根堆,遍历了 n 以内所有的素数,然后将最大的 k 个素数保存在堆中。最后,计算这 k 个素数的和并输出。
示例如下:

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

// 判断一个数是否为素数
bool is_prime(int n) {
    if (n <= 1) {
        return false;
    }
    for (int i = 2; i * i <= n; i++) {
        if (n % i == 0) {
            return false;
        }
    }
    return true;
}

// 小根堆结构体
struct min_heap {
    int capacity; // 堆容量
    int size; // 当前堆大小
    int *data; // 堆中的数据
};

// 初始化小根堆
struct min_heap* min_heap_init(int capacity) {
    struct min_heap *h = malloc(sizeof(struct min_heap));
    h->capacity = capacity;
    h->size = 0;
    h->data = malloc(sizeof(int) * capacity);
    return h;
}

// 释放小根堆
void min_heap_free(struct min_heap *h) {
    free(h->data);
    free(h);
}

// 获取父节点的下标
int parent(int i) {
    return (i - 1) / 2;
}

// 获取左右子节点的下标
int left(int i) {
    return i * 2 + 1;
}

int right(int i) {
    return i * 2 + 2;
}

// 向下调整堆
void min_heap_shift_down(struct min_heap *h, int i) {
    int l = left(i);
    int r = right(i);
    int min_index = i;
    if (l < h->size && h->data[l] < h->data[min_index]) {
        min_index = l;
    }
    if (r < h->size && h->data[r] < h->data[min_index]) {
        min_index = r;
    }
    if (min_index != i) {
        int tmp = h->data[i];
        h->data[i] = h->data[min_index];
        h->data[min_index] = tmp;
        min_heap_shift_down(h, min_index);
    }
}

// 插入数据到堆中
void min_heap_insert(struct min_heap *h, int value) {
    if (h->size < h->capacity) {
        h->data[h->size++] = value;
        int i = h->size - 1;
        while (i > 0 && h->data[i] > h->data[parent(i)]) {
            int tmp = h->data[i];
            h->data[i] = h->data[parent(i)];
            h->data[parent(i)] = tmp;
            i = parent(i);
        }
    } else if (value > h->data[0]) {
        h->data[0] = value;
        min_heap_shift_down(h, 0);
    }
}

// 计算小根堆中的数据和
int min_heap_sum(struct min_heap *h) {
    int sum = 0;
    for (int i = 0; i < h->size; i++) {
        sum += h->data[i];
    }
    return sum;
}

int main() {
    int n, k;
    scanf("%d %d", &n, &k);
    struct min_heap *h = min_heap_init(k); // 初始化小根堆
    for (int i = 1; i <= n; i++) { // 遍历 [1, n] 的所有数
        if (is_prime(i)) { // 如果是素数
            min_heap_insert(h, i); // 尝试将其插入到小根堆中
        }
    }
    printf("%d\n", min_heap_sum(h)); // 输出最大的 k 个素数的和
    for (int i = h->size - 1; i >= 1; i--) { // 从大到小输出最大的 k 个素数
        printf("%d ", h->data[i]);
    }
    printf("%d\n", h->data[0]);
    min_heap_free(h); // 释放小根堆
    return 0;
}

在上面的代码中,使用了一个自定义的小根堆数据结构,用于保存最大的 k 个素数。如果堆的大小不足 k,就可以直接添加新元素。否则,如果新元素比堆中最小的元素还要大,就将最小的元素删除并插入新元素。在计算最大的 k 个素数的和时,只需要将堆中所有元素加起来即可。最后,将最大的 k 个素数按照降序排列输出即可。