先来看一个非常简单的问题:
给定n个整数, 要求选出 K 个数, 使得选出来的 K 个数的和为 sum。
借助 dfs 来解决问题, 对每一个数, 枚举选或者不选两种情况, 我们可以用 dfs 思想来完成这样的枚举过程。
搜素过程中, 用 s 来记录当前选择的数值总和, k 用来记录选择的数的个数, deep 表示当前正在枚举第几个数是否选择。
在第一层dfs的时候, 我们可以枚举是否选第一个数, 如果选第一个数则让 s 加上第一个数且 k 加一, dfs 进入下一层; 否则 dfs 直接进入到下一层。
在第二层, 对第二个数做同样的处理, dfs 的过程中记录已经选取的数的个数, 如果已经选取了 k 个数, 判断 s 值是否等于sum。对于每一层, 我们都有两个选择-------选和不选。 不同的选择, 都会使得搜素进入完全不同得分支继续搜素。
下图是这个搜素过程对应的搜索树:
如果不选取第 i 个数, 那么 cnt 和 s 都不会有变化。
如果选取第 i 个数, cnt 加上 1 , s 加上 a[ i ]。
对于不同的选择进行不同的分支搜索。
dfs(i+1, cnt, s);
dfs(i+1, cnt+1, s+a[i]);
现在处理边界条件, 边界条件其实很简单, 当 i == n 的时候, 我们已经对所有的数都做出了选择, 这时候我们来判断选出来的数的个数是否等于 k , 和值是否等于 sum。
if(i==n){
if(cnt==k && s==sum){
ans++;
}
return;
}
调用 dfs 函数, 初始化的时候参数 i,cnt, s都应该初始化成为0。
dfs(0,0,0);
以下为完整代码:
#include <iostream>
using namespace std;
int n, k, sum, ans;
int a[40];
void dfs(int i, int cnt, int s)
{
if(i==n){
if(cnt==k && s==sum){
ans++;
}
return;
}
dfs(i+1, cnt, s);
dfs(i+1, cnt+1, s+a[i]);
}
int main() {
cin >> n >> k >> sum;
for (int i = 0; i < n; i++) {
cin >> a[i];
}
ans = 0;
dfs(0,0,0);
cout<<ans<<endl;
return 0;
}