子集和问题的一个实例为<S,c>。其中S={x1,x2,…,xn}是一个正整数的集合,c是一个正整数。子集和问题判定是否存在S的一个子集S1,使得S1中所有元素的和为c。
试设计一个解子集和问题的回溯法。
问题分析:将问题的所有解空间进行构造,得到一棵二叉树。因此,可以采用暴力求解和回溯法求解。
1、回溯法求解
#include <stdio.h>
int flag,sum=0;
int *s, *x, n,c;
void backtrack(int t)
{
int i;
if(t==n)
{
if(sum==c)
{
flag=1;
for(i=0;i<n;i++)
if(x[i])
printf("%3d",s[i]);
printf("\n");
return;
}
}
else
{
sum+=s[t];
x[t]=1;
backtrack(t+1);
x[t]=0;
sum-=s[t];
backtrack(t+1);
}
}
int main()
{
int i;
scanf("%d%d",&n,&c);
s=new int [n];
x=new int[n];
for(i=0;i<n;i++){
scanf("%d",&s[i]);
x[i]=0;
}
backtrack(0);
if(flag)
printf("yes");
else
printf("no");
return 0;
}
2、暴力搜索法求解:
#include <stdio.h>
#include <math.h>
int main()
{
int i,j;
int n,c;
int *s;
int temp,sum;
scanf("%d%d",&n,&c);
s=new int [n];
for(i=0;i<n;i++){
scanf("%d",&s[i]);
}
for(i=0;i<pow(2,n);i++)
{
temp=i; sum=0;
for(j=0;j<n;j++)
{
if(temp%2)
sum+=s[j];
temp=temp/2;
}
if(sum==c)
{
temp=i;
for(j=0;j<n;j++)
{
if(temp%2)
{
printf("%4d",s[j]);
}
temp=temp/2;
}
printf("\n");
}
}
return 0;
}
运行结果如下图所示: