题目描述:
已知 n 个整数 x1,x2,⋯,xn,以及 1 个整数 k(k<n)。从 n 个整数中任选 k 个整数相加,可分别得到一系列的和。例如当 n=4,k=3,4个整数分别为3,7,12,19 时,可得全部的组合与它们的和为:
3+7+12=22
3+7+19=29
7+12+19=38
3+12+19=34
现在,要求你计算出和为素数共有多少种。
例如上例,只有一种的和为素数:3+7+19=29。
输入格式
第一行两个空格隔开的整数 n,k(1≤n≤20,k<n)。
第二行 n 个整数,分别为 x1,x2,⋯,xn(1≤xi≤5×10^6)。
输出格式
输出一个整数,表示种类数。
输入输出样例
输入 #1
4 3
3 7 12 19
输出 #1
1
说明/提示
【题目来源】
思路及部分代码:
1. 判断素数
素数:只能被1和自己整除的数。
int prime_number(long long int n){
if(n == 2 || n == 1) return 1;
for(long long int i = 2; i<=(n/2)+1; i++){
if(n % i == 0) return 0;
}
return 1;
}
2. 递归函数
void scan(int ni, int n, int k, long long int num){
if(k <= 0){
cnt = cnt + prime_number(num);
return;
}
for(int i = ni;i < n;i++){
scan(i+1,n,k-1,num + number[i]);
}
return;
}
总代码:
#include <stdio.h>
long long int number[20] = {0};
int cnt = 0;
int prime_number(long long int n){
if(n == 2 || n == 1) return 1;
for(long long int i = 2; i<=(n/2)+1; i++){
if(n % i == 0) return 0;
}
return 1;
}
void scan(int ni, int n, int k, long long int num){
if(k <= 0){
cnt = cnt + prime_number(num);
return;
}
for(int i = ni;i < n;i++){
scan(i+1,n,k-1,num + number[i]);
}
return;
}
int main (){
int n,k;
scanf("%d %d",&n, &k);
for(int i=0;i < n; i ++){
scanf("%lld",&number[i]);
}
scan(0,n,k,0);
printf("%d",cnt);
return 0;
}
总结:
这段代码实现了一个递归函数 scan
,用于计算一组数中满足特定条件的子集的数量。其中,函数 prime_number
用于判断一个数是否为质数。然后在 main
函数中读取输入,调用 scan
函数并输出结果。
不足之处:
-
缺少输入验证: 代码中没有对输入进行充分的验证,比如输入的 n 和 k 是否在合理范围内,以及是否满足特定条件。这可能导致程序在某些情况下出现错误。
-
全局变量的使用: 全局变量
cnt
和number
可能会导致代码可读性和可维护性下降,尤其在大型程序中更容易引起混乱。 -
递归深度限制: 递归函数
scan
可能存在递归深度过深的风险,如果n
过大或者k
过大,可能导致栈溢出。 -
质数判断效率: 质数判断函数
prime_number
的效率可能不高,因为它遍历了大约一半的数来判断一个数是否为质数,可以考虑优化算法。
改进建议:
-
输入验证: 在读取输入时,应该验证输入的有效性,确保
n
和k
符合要求,避免出现不必要的错误。 -
避免全局变量: 尽量避免使用全局变量,可以将
cnt
和number
变量传递给函数,或者将它们定义在main
函数内部。 -
优化递归: 考虑优化递归函数,避免出现过深的递归调用。可以尝试使用迭代或其他方法替代递归。
-
质数判断优化: 优化质数判断函数,可以只遍历到 sqrt(n) 范围内的数进行判断,减少不必要的计算。
-
代码注释和命名: 添加适当的注释来解释代码的功能和逻辑,同时使用更具描述性的变量和函数命名,提高代码的可读性。
-
错误处理: 在可能出现错误的地方添加适当的错误处理机制,以便程序在出现异常情况时能够正确处理。