从a1开始按顺序决定每个数加或不加,在全部n个数都决定后再判断它们的和是否等于k,因为状态数是2^(n+1),所以复杂度为o(2^n)。
过程中可以实现剪枝:当走到某一步,sum>k时,可以直接return false(bool),return(void),因为若再继续搜索下去依然不能找到正确答案。
不输出数字:
#include<cstdio>
using namespace std;
int n,k;
int a[30];
bool dfs(int step,int sum)
{
if(step==n) return sum==k;//递归出口:判断前n项计算完所得的sum是否等于k
if(sum>k) return false;//剪枝->继续下去的答案肯定是错的
if(dfs(step+1,sum)) return true;//不加a[i]
if(dfs(step+1,sum+a[step])) return true;//加a[i]
return false;
}
int main()
{
scanf("%d",&n);
for(int i=0;i<n;i++)
scanf("%d",&a[i]);
scanf("%d",&k);
if(dfs(0,0)) puts("Yes");
else puts("No");
return 0;
}
输出数字:
#include<cstdio>
#include<stack>
using namespace std;
int a[30],n,k;
stack<int >num;//用栈保存数字
bool dfs(int step,int sum)
{
if(step==n) return sum==k;
if(sum>k) return false;
if(dfs(step+1,sum)) return true;
if(dfs(step+1,sum+a[step]))
{
num.push(a[step]);//先放入的是大数(深层的dfs)
return true;
}
return false;
}
int main()
{
while(~scanf("%d%d",&n,&k))
{
for(int i=0; i<n; i++)
scanf("%d",&a[i]);
if(dfs(0,0))
{
puts("Yes");
for(int i=0; !num.empty(); i++)
{
if(i) printf(" ");
printf("%d",num.top());//按照加和的顺序输出
num.pop();
}
printf("\n");
}
else puts("No");
}
return 0;
}
递归先是逐渐递到最深层判断,然后再从深层到次深层...归到第一层逐渐向stack中加入数,
最终stack的top是最先dfs的数(小数)