题意:
有n个数,从中选取k个,要求和为s,计算有多少种选数的方法。其中, k<=n<=16。
题目分析:
dfs递归求解,n个数存放在数组a内,递归函数的参数为sum、i,表示从a[i]向后选数,和为sum,选出的数放进全局变量vector容器v内。当v中元素数为k并且sum=0时,找到一种符合条件的选数方法;当i>=n或者v中元素数>k或者sum<0时,该选数方法已经不成立,不必继续下去,递归结束(可行性剪枝)。否则,分选a[i]和不选a[i]两种转移方式,若不选,sum不变,i+1继续递归;若选,将a[i]加入vector,sum-=a[i],i+1继续递归。
代码:
#include<iostream>
#include<cstdio>
#include<vector>
using namespace std;
int a[20];
int cnt;
int n,k,s; vector<int> v;
void select_num(int sum,int i){//从a[i]开始选,和为sum,保存在res
if(v.size()==k && sum==0){
cnt++;
return;
}
//搜索边界
if(i>=n) return;
//可行性剪枝
if(v.size()>k || sum<0) return;
select_num(sum,i+1);//不选a[i]
v.push_back(a[i]);
select_num(sum-a[i],i+1);//选a[i]
v.pop_back();
}
int main()
{
int t; cin>>t;
while(t--){
cnt=0; v.clear();
cin>>n>>k>>s;
for(int i=0;i<n;i++) cin>>a[i];
select_num(s,0);
cout<<cnt<<endl;
}
return 0;
}