问题描述
Given positive numbers, ZJM can select exactly of them that sums to . Now ZJM wonders how many ways to get it!( 个数中选 个数,其和等于 的方案有多少个)
Input
The first line, an integer , indicates the number of test cases. For each case, there are two lines. The first line, three integers indicate , and . The second line, integers indicate the positive numbers.
Output
For each case, an integer indicate the answer in a independent line.
Sample Input
1
10 3 10
1 2 3 4 5 6 7 8 9 10
Sample Input
4
Note
Remember that and all numbers can be stored in 32-bit integer
解题思路
这个题是一个典型的子集枚举问题,为了防止TLE,我们应该考虑一些特殊情况进行合理剪枝。
我们对这
个数进行dfs,每个数有两种选择,取或者不取。那么我们就有了两种可行性剪枝方案:
选择数的个数大于
。
已经选择数的总和大于
(由于所有数都是正数,大于
就出现错误)。
在下面的代码中使用list是为了方便调试,可以查看合法方案,单对此题来说,并没有使用list的必要,再开一个参数记录已经选择的个数即可。
完整代码
//#pragma GCC optimize(2)//比赛禁止使用!
//#pragma G++ optimize(2)
//#include <bits/stdc++.h>
#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <cmath>
#include <cstring>
#include <string>
#include <climits>
#include <algorithm>
#include <queue>
#include <vector>
#include <stack>
#include <list>
using namespace std;
const int maxn=20;
int T,n,k,s,ans,a[maxn];
list<int> l;//使用list就是为了查看当前有那些值
void dfs(int step,int sum)//step代表当前到了第几个数,sum是目前list中数的和
{
if (sum == s && l.size() == k){
ans++;
//for(auto it:l) cout<<it<<' ';//查看组成情况
//cout<<endl;
return;
}//当达到s并且数字个数达到k
if(step>n || l.size()>=k || sum>=s) return;//搜过了(此处注意应该是'>'号),个数大于k了,总和大于sum了,则返回
dfs(step+1,sum);//不取当前数,向后搜索
l.push_back(a[step]);//将当前数加入list中
dfs(step+1,sum+a[step]);//取当前数,向后搜索
l.pop_back();//将取的数弹出
}
int getint()
{
int x=0,s=1;
char ch=' ';
while(ch<'0' || ch>'9')
{
ch=getchar();
if(ch=='-') s=-1;
}
while(ch>='0' && ch<='9')
{
x=x*10+ch-'0';
ch=getchar();
}
return x*s;
}
int main()
{
ios::sync_with_stdio(false);
cin.tie(0);
cin>>T;
while(T--){
cin>>n>>k>>s;
ans=0; memset(a,0,sizeof(a));l.clear();
for (int i=1; i<=n; i++)
cin>>a[i];
dfs(1,0);
cout<<ans<<endl;
}
return 0;
}