一、题目描述:
【问题描述】子集和问题的一个实例为<S,M>。其中S={x1,x2,…,xn}是一个正整数的集合,M是一个正整数。找出S的所有子集S1,使得S1中所有元素的和为M。试设计一个解子集和问题的回溯法。
【样例输入】
5 10 12 13 15 18
30
【样例输出】
5 10 15
5 12 13
12 18
【样例说明】输入第一行是集合S,第二行是整数M;输出每一行代表一个解
二、设计思想
1、方法:递归+回溯
2、递归:back(i) 中含 back(i+1)
回溯:不放第i元素,继续 back(i+1)
3、back(i)主体:
(1)、if(i>n || Sum>SumFlag ||Num[i]>SumFlag) return; 跳出
(2)、满足条件,打印
(3)、放入第i元素,back(i+1)递归
Sum=Sum-Num[i];//回溯
不放入第i元素,back(i+1)递归
三、代码如下:
#include <bits/stdc++.h>
#define N 100000
using namespace std;
int n=6;//集合中元素个数
int Sum=0;//存目前计算的元素和
int SumFlag=0;//SumFlag值为所需求的元素和
int Num[N];//集合的元素
bool flag[N];//flag[i]=true表示放入计算,flag[i]=false表示未放入计算
void back(int i){
if(i>n || Sum>SumFlag ||Num[i]>SumFlag) return;//穷尽元素数组或者和大于SumFlag,跳出
//数组存储有数据的i最大值为n-1,将其放入flag数组为一次操作
//若其放入后,存储的元素满足题意,执行打印为一次操作使i=n
//跳出为一次操作使i=n+1
//所以此次判断为i>n,而不是i>n-1
else if(Sum==SumFlag){//满足条件,输出
for(int i=0;i<n;i++){
if(flag[i]){
cout<<Num[i]<<" ";
}
}
cout<<endl;
}
else{
Sum=Sum+Num[i];
flag[i]=true;//第i元素加入满足条件的元素组
back(i+1);//递归
Sum=Sum-Num[i];//回溯
flag[i]=false;//第i元素不加入满足条件的元素组
back(i+1);//递归
}
}
int main(){
for(int i=0;i<n;i++){//输入元素值
cin>>Num[i];
flag[i]=false;//将其对应的flag[i]设置为false
}
cin>>SumFlag;//SumFlag值为所需求的元素和
back(0);
return 0;
}
四、示例
1、示例输入:
5 10 12 13 15 18 30
2、示例输出:
5 10 15 5 12 13 12 18