[DFS+剪枝]Exercise Week3 A-选数

题意

共有n个正整数,从这n个数中选出k个数,要求其和为sum,求有多少种不同的选择方法


样例

样例输入:
第一行为一个整数T,表示有T组数据
其后每组数据有两行, 第一行有三个整数n,k,sum (k<=n<=16)
第二行有n个正整数(int型)
1
4 2 6
1 5 2 4
样例输出:
每组数据在独立的一行中输出一个方案数
2


思路

DFS:根据选或不选第i个数,进行深度优先搜索,三个参数 i , step , tnt ,分别为 当前为第i个数、当前选了step个数、当前选的数之和 当step==k时 递归停止 判断tnt是否等于sum,相等则ans++

剪枝:由于裸的DFS在本题是O(2^n),是一个很吓人的复杂度(由于本题n<=16,似乎也可以过…),故可以加一些必要的剪枝,如 在某一步 tnt 已经大于 sum了,就return ;(好吧只能想起来这一个orz)


总结

1.DFS:要仔细考虑边界的判断、递归的终止条件,比如如果不加 if(i==n+1) return 就会访问到其他未知的空间
2.剪枝:任何一个正确的剪枝都是对DFS的极大优化,故…尽量多剪点枝 ^ ^


代码

#include<iostream>
#include<algorithm>
#include<string.h>
#include<stdio.h>
using namespace std;
int n,k,sum;
int ans;
int p[100];
void dfs(int i,int step,int tnt)
{
	if(tnt>sum)	return;	//剪枝
	if(step==k)//递归终止
	{
		if(tnt==sum) ans++;
		return;
	}
	if(i==n+1)	return ;//边界条件

	dfs(i+1,step+1,tnt+p[i]);//选p[i]
	
	dfs(i+1,step,tnt);//不选p[i]
} 
int main()
{
	int T;
	cin>>T;
	while(T--)
	{
		ans=0;
		cin>>n>>k>>sum;
		for(int i=1;i<=n;i++)	cin>>p[i];
		dfs(1,0,0);
		cout<<ans<<endl;
	} 
	system("pause");
	return 0;
} 
发布了12 篇原创文章 · 获赞 0 · 访问量 518

猜你喜欢

转载自blog.csdn.net/linshen_jianhai/article/details/104697600