题目:
给定n个正数,ZJM可以精确地选择其中的K个使它们之和为S。现在ZJM想知道有多少种方法可以得到它!
Input:
第一行是一个整数T<=100,表示测试用例的数量。对于每种情况,有两行。第一行,三个整数分别表示n, K和S。第二行,n个正整数。
Output:
对于每种情况,一个整数在独立的行中表示答案。
Example:
Input:
1
10 3 10
1 2 3 4 5 6 7 8 9 10
Output:
4
Note:
记住,k<=n<=16k<=n<=16,所有数字都可以存储为32位整数。
题目分析:
该题为选数问题,采用DFS深度搜索的思想,遍历这N个数,但是因为DFS是从一个点一直往下搜索直到没有可搜索的顶点再回溯,增加时间复杂度的同时又可能面对无解的情况。 所以这个时候可以增加一些判断条件来进行可行性剪枝,在选数问题上,当选的点数量超过K个或者已选数的和超过s,即不符合条件可以将其剪去。
代码:
#include<iostream>
#include<algorithm>
#include<list>
using namespace std;
const int maxn=1e3+5;
int a[maxn];
int n,k,s;
int ans;
void solve(int i,int sum,list<int> &res)//i为数的下标,sum为还需要选的数的和,res为存储已选数的list
{
if(res.size()==k &&sum==0)//当已选数个数为k或者已选数的和已达s 找到答案
{
ans++;//方法+1
return ;
}
if(i>n) return ;// 搜索边界
if(res.size()>k||sum<0) return ;//可行性剪枝
solve(i+1,sum,res);
res.push_back(a[i]);
solve(i+1,sum-a[i],res);
res.pop_back();
}
int main()
{
int T;
cin>>T;
for(int i=0;i<T;i++)
{
cin>>n>>k>>s;
for(int j=1;j<=n;j++)
{
cin>>a[j];
}
ans=0;
list<int> my_list;//定义list
solve(1,s,my_list);
cout<<ans<<endl;
}
}
list my_list;一定要放在for循环里面进行定义并且初始化,这样在执行每一次for循环的时候才不会出错,否则vj运行会报wrong answer on test2。