【回溯法】子集合问题

一、题目描述:

【问题描述】子集和问题的一个实例为<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

  • 1
    点赞
  • 16
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

怪&

感谢您的支持

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值