题目描述
给定整数a1、a2、…an,判断是否可以从中选出若干数,使它们的和恰好为K。
输入
首先,n和k,n表示数的个数,k表示数的和。
接着一行n个数。
(1<=n<=20,保证不超int范围)
输出
如果和恰好可以为k,输出“YES”,并按输入顺序依次输出是由哪几个数的和组成,否则“NO”
样例输入
4 13
1 2 4 7
样例输出
YES
2 4 7
这是一道简单的深度优先搜索算法题,因为 n<=20,所以容易想到暴力法,但是这道题并没有说明组合数的个数,也就是说可以是1个数符合,也可以3个4个数符合,这样我们写for循环时,时间复杂度就会很高,很难通过OJ。
使用深度搜索,递归会把所有情况都考虑在内,只需要写dfs函数就可以搞定。
直接上代码!
#include<stdio.h>
#include<stdlib.h>
#include<math.h>
#include<string.h>
int n,sum;
int s=0,f=0;
int a[30],b[30];
void dfs(int x)
{
int i,k;
if(s>=sum) //还是老样子,函数需要先写结束条件,判断是否结束
{ //这道题里当s大于条件和时,就没必要再进行递归了,直接进行判断
if(s==sum) //当s等于条件和
{
if(f==0) //f是判断时候有符合条件的输出,当没有符合的时,f始终为0
f=1;
if(f)
{ //符合条件,输出
printf("Yes\n");
for(i=0; i<n; i++) //所有数的下表
{
if(b[i]) //利用数组b判断是否需要输出
printf("%d ",a[i]);
}
printf("\n");
}
}
}
for(k=x; k<n; k++)
{
s=s+a[k]; //当前元素,加和 s
b[k]=1; //当前元素的下标,在数组b中标记为1
dfs(k+1); //进入下个dfs
s=s-a[k]; //回溯,减去加上的元素
b[k]=0; //回溯,把数组b中标记的1返回为0,以便于下次dfs使用
}
}
int main()
{
int i,j,k;
memset(b,0,sizeof(b)); //把数组b全部设为0,便于标记
scanf("%d %d",&n,&sum);
for(i=0; i<n; i++)
{
scanf("%d",&a[i]);
}
dfs(0); //从第一个数进入dfs
if(f==0) //此时递归结束,如果f仍为0,则说明没有符合条件的组合
printf("No\n");
return 0;
}