题目描述:
Given n positive numbers, ZJM can select exactly K of them that sums to S. Now ZJM wonders how many ways to get it!
输入:
The first line, an integer T<=100, indicates the number of test cases. For each case, there are two lines. The first line, three integers indicate n, K and S. The second line, n integers indicate the positive numbers.
输出:
For each case, an integer indicate the answer in a independent line.
example:
Input
1
10 3 10
1 2 3 4 5 6 7 8 9 10
Output
4
提示:
Remember that k<=n<=16 and all numbers can be stored in 32-bit integer
题目思路:
对于选数问题,我们想到的操作就是dfs,在dfs过程中我们可以选择一个数然后往下深入,对于每个数可以选择和不选择,这样就可以列举所有的情况,为2^n种,但是这个题没有必要列举所有的情况,在这里我们称之为剪枝。
首先,如果选择的个数超过了k个,那么就不用再选择了,而是判断他们的和是不是s,其次,如果和是s的话就方法数目++,不是的话应该倒回到起始状态重新选择。
还要注意本题输出的是方法的个数,而且是多次操作,所以记录可行的方法的个数的时候不能单独用一个全局变量,而是在dfs内部统计好操作次数之后返回到main里面赋值给对应的变量。那么我们设计的时候就要先遍历把每个变量都选一遍试试,如果到了选择的个数就比较和是不是s,是的话就返回1,而对于num来说返回1就是方法个数+1,返回0就是不变,所有操作完成之后就可以返回操作的方法数了。
int dfs(int n,int sum,int start,int end)
{
if(n==0)
{
if(sum==s)
return true;
else
return false;
}
int num=0;
for(int i=start;i<=end;i++)
{
num=num+dfs(n-1,sum+a[i],i+1,end);
}
return num;
}
同时也要注意这个变量每次要清零,否则会错误。
int num=0;
代码如下:
#include<iostream>
using namespace std;
int a[1000000];
int n,k,s;
int dfs(int n,int sum,int start,int end)
{//n为剩余选择的个数,初始就是题目中的k,sum为递归过程中的和,最后要和s比较,start和end就是选择的开始与结束,那么本题就是开始的位置依次往后,然后每个开始的位置都for一遍选择
if(n==0)
{
if(sum==s)
return true;
else
return false;
}
int num=0;
for(int i=start;i<=end;i++)
{
num=num+dfs(n-1,sum+a[i],i+1,end);//这里可以记录方法的个数,就在于前面返回值是1还是0,返回1的话救赎num+=1,返回0就不变
}
return num;
}
int main()
{
int t;
cin>>t;
for(int i=1;i<=t;i++)
{
int num=0;
cin>>n>>k>>s;
for(int j=0;j<n;j++)
{
cin>>a[j];
}
num=dfs(k,0,0,n-1);
cout<<num<<endl;
}
}
运行结果: