子集和问题(dfs)

题目

子集和问题的一个实例为。其中,S={x1,x2,…,xn}是一个正整数的集合,c是一个正整数。子集和问题判定是否存在S的一个子集S1,使得子集S1和等于c。
对于给定的正整数的集合S={x1,x2,…,xn}和正整数c,编程计算S 的一个子集S1,使得子集S1和等于c。

输入

第1行有2个正整数n和c,n表示S的个数,c是子集和的目标值。接下来的1 行中,有n个正整数,表示集合S中的元素。

输出

输出一个解即可,如果没有解,输出“No Solution!”。

样例输入

5 10
2 2 6 5 4

样例输出

2 2 6

分析

使用深度优先(dfs)可以很容易解决。设立一个flag数组用来标记第i个数字是否已经被引用,设立一个cnt来记录是都找到解,如果找到结束搜索。写dfs函数时间传入两个值,一个来表示是否已经遍历所有的项,一个来记录数字和。分左右两枝来进行搜索。

子集和问题(dfs)_第1张图片

 代码实现

#include 
using namespace std;
typedef long long ll;

ll n,c;
ll a[1000005];
bool flag[1000005];//定义bool类型的数组,标记数字的使用与否; 
ll cnt=0,sum=0;

void dfs(ll t,ll w)
{
	if(cnt==1)//如果已经找到一组,返回空,结束深搜;
		return;
	// 深度搜索的终止条件;
	if(t==n+1)
	{
		if(w==c)//搜索到符合条件的值,进行输出这一组解; 
		{
			for(ll i=1;i<=n;i++)
			{
				if(flag[i]==1)
				{
					printf("%lld ",a[i]);
				}
			}
			cnt++;//找到一组cnt+1作为标记; 
		}
		return;
	}
	if(w>c)//如果已经使用的数字和大于所需,在往下搜索就不可能满足要求; 
		return;//因为往下已经不可能满足要求了,所以进行截枝,节省时间; 
	//左枝,即使用这个数; 
	flag[t]=1;//将这个数标记为 1,即使用该数; 
	dfs(t+1,w+a[t]);//递归深搜 
	//右枝,即不使用这个数; 
	flag[t]=0;//将这一数字标记为0,即没有使用这一数字; 
	dfs(t+1,w);//递归深搜 
}

int main()
{
	cin>>n>>c; 
	for(ll i=1;i<=n;i++)
	{
		scanf("%lld",&a[i]);
		sum+=a[i];//求数字的和; 
	}
	if(sum

你可能感兴趣的:(训练赛,深度优先,算法,c++)