A-选数问题

题目:

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

题目分析:

该题为选数问题,采用DFS深度搜索的思想,遍历这N个数,但是因为DFS是从一个点一直往下搜索直到没有可搜索的顶点再回溯,增加时间复杂度的同时又可能面对无解的情况。 所以这个时候可以增加一些判断条件来进行可行性剪枝,在选数问题上,当选的点数量超过K个或者已选数的和超过s,即不符合条件可以将其剪去。

代码:

#include<iostream>
#include<algorithm>
#include<list>
using namespace std;
const int maxn=1e3+5;
int a[maxn];

int n,k,s;
int ans;
void solve(int i,int sum,list<int> &res)//i为数的下标,sum为还需要选的数的和,res为存储已选数的list
{
	if(res.size()==k &&sum==0)//当已选数个数为k或者已选数的和已达s 找到答案 
	{
		ans++;//方法+1
		return ;
	}
	if(i>n) return ;// 搜索边界 
	if(res.size()>k||sum<0) return ;//可行性剪枝 
	solve(i+1,sum,res);
	res.push_back(a[i]);
	solve(i+1,sum-a[i],res);
	res.pop_back();
}
int main()
{
	int T;
	cin>>T;
	for(int i=0;i<T;i++)
	{
		cin>>n>>k>>s;
		for(int j=1;j<=n;j++)
		{
			cin>>a[j];
		}
		ans=0;
		list<int> my_list;//定义list
		solve(1,s,my_list);
		cout<<ans<<endl;
	}
} 

list my_list;一定要放在for循环里面进行定义并且初始化,这样在执行每一次for循环的时候才不会出错,否则vj运行会报wrong answer on test2。

样例运行:

在这里插入图片描述

发布了15 篇原创文章 · 获赞 0 · 访问量 804

猜你喜欢

转载自blog.csdn.net/qq_43746837/article/details/104732780