dfs--选数

题目描述

给定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位整数。

解题思路

本题的思路可以由简单到复杂一步步深入。首先可想到的最“硬核”的解题方法就是:每个数都有取或不取这两种可能,因此可以直接用最简单的递归解决。但考虑到时间复杂度过高的问题,要想办法对算法进行优化。根据递归过程分析,优化的方法可以从两种角度分析:选取数的个数和和的大小,即当选取数的个数超过指定个数,或者和的大小超过指定和时,都可以跳过此次递归。
由于考虑到选数是一个依次进行的过程,因此才选用递归的方法实现。

代码

#include<iostream>
using namespace std;
int n,k,s,num[16];
int number;
void select(int i,int m,int sum,int *num)//i记录数组第几个,m记录选了的个数 
{
	if(sum==s&&m==k)//找到符合条件的一种情况,number+1
	{number++; return ;}
	if(sum>s||m>k) return ;//这种情况不符合要求,直接返回
	if(i>=n) return; //数组遍历结束,返回
	
	select(i+1,m,sum,num);//没选 
	select(i+1,m+1,sum+num[i],num);//选了 
}
int main()
{
	int t,m,sum;
	cin>>t;//t是总共测试示例的个数 
	for(m=0;m<t;m++)
	{
		number=0;//number是需要输出的取数方法个数,初始为0 
		sum=0;//当前的和的大小 
		cin>>n>>k>>s;//数组大小,几个数字求和,以及需要满足的和的大小 
		for(int i=0;i<n;i++)
		    cin>>num[i];//数组值 
        select(0,0,sum,num);
        cout<<number<<endl;
	}
	return 0;
 } 

反思

做一道题的重要思路是从最简单最容易的想法入手,然后再一步步优化,这样就能保证思路的正确,而且是一种做题的通用思路。在这过程中优化的方式通常会从时间复杂度的方向考虑。

发布了16 篇原创文章 · 获赞 0 · 访问量 221

猜你喜欢

转载自blog.csdn.net/weixin_43679657/article/details/105002720