问题描述
子集和问题的一个实力为<S,c>。其中,S= { w1,w2,w3,...wn}是一个正整数的集合,c是一个正整数。判定是否存在S的一个子集S1使得S1的和为c。
输入:
输入含多组测试用例!
对每组测试用例,第一行有两个正整数n和c,n表示S的大小,c是子集和的目标值。接下来的一行,有n个正整数(1<= n <= 10000),表示集合S中的元素。当n=c=0时输入结束。
输出
输出子集和问题的全部解,每个数据后面都有一个空格。当问题无解时,输出“No Solution!"。
输入样例:
5 10
2 2 6 5 4
5 3
2 2 6 5 4
0 0
输出样例:
2 2 6
6 4
No Solution!
算法分析
用回溯法解决子集和问题,与0-1背包问题类似,解空间树是一颗子树。采用深度优先策略,算法只记录当前路径。
代码:
#include <stdio.h>
#include <iostream>
#include <stdlib.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define maxN 10001
int n,c;
int a[maxN],x[maxN];
int cw,bestw,sum,r;
void backtrack(int t)
{
if( t > n)
{
if( cw == c ) {
sum ++;
for(int i = 1; i <= n; i++)
if(x[i] == 1)
printf("%d ",a[i]);
printf("\n");
}
return ;
}
r -= a[t];
if(cw + a[t] <= c)
{
x[t] = 1;
cw += a[t];
backtrack(t+1);
cw -= a[t];
}
if(cw + r >= c)
{
x[t] = 0;
backtrack(t+1);
}
r += a[t];
}
int main()
{
freopen("subset.txt","r",stdin);
while(scanf("%d %d",&n,&c) && n!=0)
{
r = 0;
sum = 0;
for(int i = 1; i <= n; i++)
{
scanf("%d",&a[i]);
r += a[i];
}
backtrack(1);
if(sum == 0) printf("No Solution!\n");
}
return 0;
}