[输入样例]
4 3 3 7 12 19
[输出样例]
1
[解题思路]
给我们n个数,让我们任选其中k个数并求和,求使这个和为素数的组合共有多少种。对于这种多选多的模型,我们可以用dfs的方法递归求出符合条件的总数。
需要注意的是,如果两次选取的数相同,则他们的和也相同,这应该认为是同一种情况,因此,我们必须要想一个办法,保证递归过程中无重复的选取组合。
具体实现方式如下:我们枚举第一次选取的数,接下来选取的每个数都满足在数组中的位置大于前一个数,这样,我们就能不重复地完成所有组合的遍历。
接下来就是代码部分:
#include#include using namespace std; //判断是否为素数 bool isPrime(int n) { bool ret = true; for (int i = 2; i * i <= n; i++) { if (n % i == 0) { ret = false; break; } } return ret; } //传入参数:数组arr、还需继续选取个数k、所选定的数之和sum(缺省值为0)、开始搜索下一个数的起始位置pos(缺省值为0) int dfs(vector arr, int k, int sum = 0, int pos = 0) { //如果无需继续选取数,则判断总和是否为素数,直接返回isPrime的结果 if (k == 0) { return isPrime(sum); } //若k>0,则继续选取下一个数 int ret = 0; for (int i = pos; i < arr.size(); i++) { //调用递归选取下一个数时需要改变的参数:还需继续选取的个数k减去1,sum加上选取的这个数的值,下一次搜索的起始位置为本次搜索的位置+1 ret += dfs(arr, k - 1, sum + arr[i], i + 1); } return ret; } int main() { //参数读取及arr的声明和初始化 int n, k; cin >> n >> k; vector arr; while (n--) { int t; cin >> t; arr.push_back(t); } //调用dfs并打印 cout << dfs(arr, k); return 0; }
接下来,我们来看一道可以用类似解法解出的题目。
-P1025 [NOIP2001 提高组] 数的划分-[输入样例]
7 3
[输出样例]
4
[详解]
#includeusing namespace std; //传入参数:需要分割的数num,剩余需要分割的数目k,上一次分割出的数 int dfs(int num, int k, int pre_part = 1) { //若需要分割的数目为1,则说明该分割方式有效,返回1 if (k == 1) return 1; //若num小于需要分割的个数,则说明该方案不可行,返回0 if (num < k) return 0; //若还能继续分割,进行递归计算有效分割个数 int ret = 0; //这里解释一下为什么从pre_part开始枚举:由于1,1,5、1,5,1、5,1,1属于同一种分割, //为了避免分割方式重复,我们只要保证每一次后分割出的数大于等于前一次分割出的数即可 //同时,由于我们分割出的数满足非严格递增,我们枚举第一次分割出的数一定小于等于num/2 for (int i = pre_part; i <= num / 2; i++) { ret += dfs(num - i, k - 1, i); } return ret; } int main() { int num, k; cin >> num >> k; cout << dfs(num, k, 1); return 0; }


![[C++]洛谷 选数&&数的划分 dfs方法详解 [C++]洛谷 选数&&数的划分 dfs方法详解](http://www.mshxw.com/aiimages/31/849492.png)
