本关任务:输入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 个素数按照降序排列输出即可。