# [NOIP2002 普及组] 选数
## 题目描述
已知 n个整数x1,x2,x3......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,x3.......xn(1 <= x <= 5 X 10^6) 。
## 输出格式
输出一个整数,表示种类数。
## 样例 #1
### 样例输入 #1
```
4 3
3 7 12 19
```
### 样例输出 #1
```
1
```
思路:毕竟刚学dfs,并不理解具体含义,便拿着全排列的模版上去改,开始的时候便卡在了怎么控制几个数的相加,之后去看了看书和视频什么的大概理解了点解决了这个点。
之后再一看题干:要求你计算出和为素数共有多少种。
也就是说不能光计算和是否为素数单纯进行计数器加一,还得查重。
在琢磨了一会之后去看了题解,了解了用升序来避免重复。(下面代码中会说到)
解决了这个问题后其他便没什么问题了。
代码如下:
#include <iostream>
using namespace std;
bool check (int x)//判断素数
{
if(x == 1)
{
return 0;
}
for(int i = 2; i * i <= x; i ++ )
{
if(x % i == 0)
{
return 0;
}
}
return 1;
}
int k,n;
int arr[103];
long long num;
void dfs(int a, int b, int c)//a为当前挑选数字个数,b为数字的和,c为进行升序的判断
{
if(a == k)
{
if(check(b))
{
num ++;
}
return ;
}
for (int i = c; i < n; i++)
{
dfs(a + 1,b + arr[i],i + 1);//递归,步数加一,和加上,升序加1防止重复
}
return ;//枚举结束返回
}
int main()
{
scanf("%d%d",&n,&k);
for(int i = 0; i < n; i ++ )
{
scanf("%d",&arr[i]);
}
dfs(0,0,0);
printf("%d\n",num);
return 0;
}
升序介绍:从 for (int i = c; i < n; i++) 这一步开始就是,具体如下解释:
正如例子所给:3 + 9 + 12 这种。
是否可以想到一种很基本的方法,让每一位的数从小到大进行加法操作:
1 2 3 4 5
1 + 2 + 3
1 + 2 + 4
1 + 2 + 5
接下来让第二位变大
1 + 3 + 4
同理递推。
大抵,就是这样了,看了看别人的题解后自己进行了二创总结。
第一篇博客。
无了。