选数问题

题目要求

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:
在这里插入图片描述

思路

  1. 通过递归实现数字全排列,使用vector来记录已经被选中的数字,使用全局变量来记录符合要求的序列个数,初始化为0.

  2. 因为已知要找的组合是K个数字的和等于S,所以可以用剩余量 = S - 已经找到的数的和作为递归函数的参数,这样可以直接判断剩余量是否为零来确定所选择的数字之和是否等于S.

  3. 可行性剪枝: 递归过程中进行判断,对不符合要求的全排列及时终止,有三个判断:
    (1) 判断vector中元素个数等于K,同时剩余量等于0,满足要求,全局变量加一.
    (2) 剩余量小于0,说明选中的数字之和大于S,显然,若此时vector中元素个数小于等于K,该序列不满足要求,若此时vector中元素个数大于K,则当vector中元素个数等于K时,剩余量不等于0,该序列不满足要求。
    (3) 判断vector中元素个数大于K,该序列一定不满足要求。
    (4) 已经对n个元素进行了选择,为选出符合要求的组合,该序列不满足要求
    对(2)、(3)、(4)三种情况进行处理,可以减少不必要的递归。

  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;
	}
	
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值