本题的核心是求解数组合,因为此题比较简单可以使用两层for循环暴力求解,也可以使用回溯+递归进行求解,本人选择的是第二种。
递归:将未知的问题缩小,知道访问到已知问题,便开始返回数值,知道解决未知的问题。
组合数本质上是二叉树。
假设我们要在{1,2,3,4,5}中任取3个进行组合,则有
因为我们仅仅是求组合,而不需要排列,又因为组合中的数是无序且不重复的,所以取过的 元素便不能再取避免重复。
而每个数都有取和不取两种结果,而回溯法就是模拟上图路径。
接下来上代码
#include <bits/stdc++.h>
using namespace std;
const int N = 30;
int x[N];
int n, k, p, ans;
int isprime(int m)//判断素数
{
for (int i = 2; i*i <= m; ++i)
{
if (m % i == 0)
return 0;
}
return 1;
}
void dfs(int q, int num, int sum)
{
//q是我们要确定第q个数是否需要选
//num是确定我们一共选了多少个数
//sum是确定我们取的数的总和
if (q > n)//终止条件:是否所有数都选过了,即是否达到了树的叶子结点
{
if (num == k)//判断选的数是否够了要求的数
{
ans += isprime(sum);//判断素数并且相加
}
return;
}
dfs(q + 1, num + 1, sum + x[q]);//搜索q并且把q纳入其中一个组合数的集合中
dfs(q + 1, num, sum);//搜索q但是没有选择把q纳入其中一个组合数的集合中
}
int main()
{
ans = 0;
cin >> n >> k;
for (int i = 1; i <= n; ++i)
cin >> x[i];
dfs(1, 0, 0);//从1开始进行组合
cout << ans << endl;
return 0;
}