选数问题:给定n个数字,从中选择k个使他们的和为s,求有几种组合方式。c++

选数问题

给定n个数字,从中选择k个使他们的和为s,求有几种组合方式。
第一行会给一个T(T<=100),表示测试数据的组数,每一组中有两行,第一行中有三个数字n,k,s;第二行给定n个数字。
将可能的组合方式数输出。保证k<=n<=16,所有的数字范围都在32位整数的表示范围内。

sample input:
1
10 3 10
1 2 3 4 5 6 7 8 9 10

sample output:
4

思路:

  1. 由于题目给定了数字范围不会太大,所以当然可以无脑暴力,写个循环,每次保证第i个数被取到,再嵌套循环取i+1位置的数字,循环检查是否能k个数字加起来等于s,若等于就count++;最后输出count就可以。
  2. 可以使用递归的方式来解决,其实原理比较像深搜(一条树的分支走到黑然后返回),需要判断的就是他的结束条件,只有当k==0(可以用的数字用完了)并且sum == 0(恰好等于想得到的值)才说明这个选择是对的,返回值1。
  3. 对于每一层递归,相当于是一个二叉树,有两个选择方向:选择当前数或者不选择;对他们的结果求和就能返回答案。
  4. 对于判断条件(begin>=length)一定要注意他放置的位置,需要在判断完+1之后再判断是否大于等于,如果需要选择的数字在最后一位的话,将该判断条件放到前面会导致
    组合方式缺少。或者可以写两个判断条件,先判断if(begin>length),在完成成功判断后,再判断一遍if(begin>=length)
  5. 由于这里我们需要计算数组的长度,所以最好使用动态数组,如果自己创建数组的话需要注意,将数组传入函数后,使用sizeof(a)来做是错误的,他会返回数组的大小*8,返回地址长度,所以比较建议使用vector,并用size()取数组长度。
#include <iostream>
#include <string>
#include <algorithm>
#include<cstdio>
#include<vector>

using namespace std;

ind(vector<int> a,int begin,int k,int sum)
{
	int length=a.size();

	if(k==0&&sum!=0)	return 0;//sum不对
	if(k==0&&sum==0)	return 1;
	if(begin>=length)	return 0;//这里一定一定一定要在这里,不能放在前面判断;如果输出的是最后一个数,需要在n+1位置上返回 
	return find(a,begin+1,k-1,sum-a[begin])+find(a,begin+1,k,sum);//向下检索,选择当前数或者不选择
}
int main()
{
	int t=0;
	cin>>t;
	while(t--)
	{
		vector<int> arr;
		int n=0,k=0,s=0;
		cin>>n>>k>>s;
		for(int i=0;i<n;i++)
		{
			int temp=0;
			cin>>temp;
			arr.push_back(temp);
		}
		int ans=find(arr,0,k,s);
		cout<<ans<<endl;
	}
	return 0;
 }
发布了29 篇原创文章 · 获赞 1 · 访问量 956

猜你喜欢

转载自blog.csdn.net/qq_44654498/article/details/104671293