题目描述:子集和问题的一个实例为〈S,t〉。其中,S={ 1 x , 2 x ,…, n x }是一个正整数的集合,c是一个正整数。子集和问题判定是否存在S的一个子集S1,使得s1中的各元素之和等于c。
----题目出自《计算机算法设计与分析 第3版》 王晓东
思路:用回溯法解这道题,我本来想修改排列树使之可以求出一个集合的所有子集。但是分析了一下,时间复杂度比求全排列并没有多少减少。所以就直接求出全排列来解除此题。(想通了,求子集应该用子集树来解决)
注:这个题用子集树解更简单,时间复杂度更低。类似于0-1背包的回溯法。
代码如下:
#include <stdio.h>
#include <conio.h>
#define MAX 1000
//global variables
int n=0;//the number of numbers
int c=0;//the sum of the subset
int num[MAX]={0};
int count=1;//the number of the element in a subset
int result[MAX]={0}; //the answer of this question
int c_sum=0;//current sum
//prototypes
void swap(int &a,int &b);
void back_subset(int i);
int main()
{
//declaration
int i=0;
printf("Please input the number of the numbers:");
scanf("%d",&n);
printf("Please input the sum:");
scanf("%d",&c);
for(i=1;i<=n;i++)
scanf("%d",&num[i]);
back_subset(1);
getch();
}
void back_subset(int i)
{
if(c_sum+num[i]==c)
{
result[count]=num[i];
for(int temp=1;temp<=count;temp++)
printf("%d ",result[temp]);
printf("\n\n\n\n----------separate line------------------\n\n\n\n");
return ;
}
if(i>n)
return ;
if(c_sum+num[i]>c)
return;
for(int j=i;j<=n;j++)
{
result[count++]=num[j];
c_sum+=num[j];
swap(num[i],num[j]);
back_subset(i+1);
swap(num[i],num[j]);
c_sum-=num[j];
count--;
}
}
void swap(int &a,int &b)
{
int temp=a;
a=b;
b=temp;
}
总结:
1.遗留一个问题:如何求出一个集合的所有子集? 问题已经解决:用子集树来求解。这是一个很典型的子集树问题
2.加深了我对递归退出条件的逻辑顺序的理解。
参考资料:《计算机算法设计与分析 第3版》 王晓东