题目描述:
已知 nnn 个整数 x1,x2,⋯ ,xn,以及 1 个整数 k(k<n)。从 n 个整数中任选 k 个整数相加,可分别得到一系列的和。例如当 n=4,k=3,4 个整数分别为 3,7,12,19时,可得全部的组合与它们的和为:
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×106)。
输出格式
输出一个整数,表示种类数。
思路
不降原则
因为是求种类数 ,所以需要去重,有点麻烦,所以就按照从大到小的顺序全排列
例如,在1 2 3 4,四个数字中选三个数字
1 2 3
1 2 4
2 3 4
因为123跟213,231,312…虽然顺序不同,但是本体是求和,他们的和都相等,是重复的结果
所以,从大到小输出,避免重复
具体实现,看下列代码,dfs函数的参数y,就代表当前选择的数字在全部数字中的位置是第y个,
for循环也是从第y个开始,省去了循环的时间,而且也在避免重复
之后dfs递归y+1,自动选择比它大的数字进行排序
void dfs(int x, int s, int y) {
if (x == k && primer(s)) {
cnt++;
return ;
}
if (x >= k) return;
for(int i = y; i < n; i++) {
if (!book[i]) {
dfs(x + 1, s + a[i], i + 1);
}
}
}
代码详情
#include<stdio.h>
#include<string.h>
#include<math.h>
//普通方法现在我有点写不出来,只能学dalao的不降原则
int a[30], n, k, cnt;
//int book[30];不用标记了,直接按大小选数字
//函数,判断是否是素数
int prime(int t) {
int p = sqrt(t);
if(t == 1)return 0;
for(int i = 2; i <= p; i++) {
if (t % i == 0)return 0;
}
return 1;
}
//x 现在是第几个数
//s 现在x个数的和
//y 选的第x个数 在所有的数中排第几
void dfs(int x, int s, int y) {
if (x == k && primer(s)) {
cnt++;
return ;
}
if (x >= k) return;
for(int i = y; i < n; i++) {
if (!book[i]) {
// book[i] = 1;
// s += a[i];
// if (x == k && primer(s)) cnt++;
dfs(x + 1, s + a[i], i + 1);
// s -= a[i];
// book[i] = 0;
}
}
// dfs(x+1, s);
}
int main() {
scanf("%d%d", &n, &k);
for (int i = 0; i < n; i++) {
scanf("%d", &a[i]);
}
dfs(0, 0, 0);
printf("%d", cnt);
}