题目要求
Given n positive numbers, ZJM can select exactly K of them that sums to S. Now ZJM wonders how many ways to get it!
Input:
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.
Output:
For each case, an integer indicate the answer in a independent line.
Example:
思路
-
通过
递归
实现数字全排列,使用vector
来记录已经被选中的数字,使用全局变量来记录符合要求的序列个数,初始化为0. -
因为已知要找的组合是K个数字的和等于S,所以可以用
剩余量 = S - 已经找到的数的和
作为递归函数的参数,这样可以直接判断剩余量是否为零来确定所选择的数字之和是否等于S. -
可行性剪枝
: 递归过程中进行判断,对不符合要求的全排列及时终止,有三个判断:
(1) 判断vector中元素个数等于K,同时剩余量等于0,满足要求,全局变量加一.
(2) 剩余量小于0,说明选中的数字之和大于S,显然,若此时vector中元素个数小于等于K,该序列不满足要求,若此时vector中元素个数大于K,则当vector中元素个数等于K时,剩余量不等于0,该序列不满足要求。
(3) 判断vector中元素个数大于K,该序列一定不满足要求。
(4) 已经对n个元素进行了选择,为选出符合要求的组合,该序列不满足要求
对(2)、(3)、(4)三种情况进行处理,可以减少不必要的递归。 -
递归时,每个元素都有选与不选两种可能,所以共有2^n种组合,通过向vector中压入和弹出遍历所有组合.
choosenumber(p, arr, size, _k, sum, icurrent + 1);//不选该元素,对应剩余量sum不变
p.push_back(arr[icurrent]);//选该元素,对应剩余量 为 原剩余量-该元素
choosenumber(p, arr, size, _k, sum - arr[icurrent], icurrent + 1);
p.pop_back();//弹出该元素
代码
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int thecount;
void choosenumber(vector<int>& p,int* arr, int size, int _k, int sum ,int icurrent)
{
if (p.size() > _k)
return;
if (sum < 0)
return;
if (sum == 0 && p.size() == _k)
{
thecount++;
return;
}
if (icurrent >= size) return;
choosenumber(p, arr, size, _k, sum, icurrent + 1);
p.push_back(arr[icurrent]);
choosenumber(p, arr, size, _k, sum - arr[icurrent], icurrent + 1);
p.pop_back();
}
int main()
{
int t, n, s, k;
cin >> t;
for (int i = 0; i < t; i++)
{
cin >> n >> k >> s;
int* num = new int[n];
for (int j = 0; j < n; j++)
{
cin >> num[j];
}
int temp = 0;
thecount = 0;
vector<int> demo;
choosenumber(demo, num, n, k, s, 0 );
cout << thecount << endl;
}
}