子集合问题(回溯)

问题描述:子集和问题的一个实例为<S, t>。其中,S={x, x2, .. xn}是一个正整数的集合,c是一个正整数。子集和问题判定是否存在S的一个子集S1,使得

试设计一个解子集和问题的回溯法。

 

算法的基本思想

①解向量:n个分量的向量(x1,x2,x3,……xn) xi=0/1,0表示不选取,1表示选取

解空间:子集树,集合中的每个元素选取/不选取

②显式约束函数:子集合中已有元素的和+元素x>c

隐式约束函数:子集合中已有元素的和+剩余未访问的所有元素的和<c

③集合中第一个元素作为根节点,深度优先遍历子集树,将求的的解向量输出到文件。

 

时间性能:遍历子集树O(2^n)

空间性能:存储路径信息和元素值,O(n)

#include <iostream>
#include <fstream>
using namespace std;
class SubGroup{
	public:
	    void Backtrack(int); 
	    void output();
	    int rest(int);
		SubGroup(int n,int c,int *a){
			this->n=n;
			this->c=c;
			currc=0;
			x=new int[n];
			w=new int[n];
			for(int i=0;i<n;i++)
				w[i]=a[i];
			found=false;
		}
		bool found;	
	private:
		int n;
		int c;
		int currc;//当前累加值 
		int *x;//路径信息 
		int *w;// 值 
};
ifstream in("input.txt");
ofstream out("output.txt");

void SubGroup::output(){
	for(int i=0;i<n;i++)
		if(x[i])
			out<<w[i]<<' ';
	out<<'\n';
}

int SubGroup::rest(int t){
	int sum=0;
	for(int i=t;i<n;i++)
		sum+=w[i];
	return sum;
}

void SubGroup::Backtrack(int t){
	if(t==n){//到达叶子节点 ,得到了可行解 
		output();	
		found=true;
		return;
	}
	//左子树
	if(w[t]+currc<=c){
		currc+=w[t];
		x[t]=1;
		Backtrack(t+1);
		x[t]=0;
		currc-=w[t];
	}
	//右子树
	x[t]=0;
	if(currc+rest(t+1)<c) //剪枝 
		return;//回溯
	else
		Backtrack(t+1); 
}
int main(){
	int n,c,i=0;
	while(in>>n){
		in>>c;
		int x[n];
		for(int i=0;i<n;i++)
			in>>x[i];
		SubGroup sb(n,c,x);
		sb.Backtrack(0);
		if(!sb.found) 
			out<<"No Solution!"<<'\n';
	}
	in.close();
	out.close();
	return 0;
} 

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

打赏作者

hnu哈哈

请接受直女的么么哒????

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

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

打赏作者

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

抵扣说明:

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

余额充值