求解幂集问题、简单0/1背包问题

幂集问题

一、问题描述

        对于给定的正整数n(n>=1),求1~n构成的集合的幂集(即由1~n的集合中所有自己构成的集合,包括全集和空集)。

二、解法

1、直接穷举法:将1~n存放到数组a中,用b数组中1~n的元素来标记(0为不在当前集合,1为在当前集合),此时便可将问题转化为:例如,n=3,幂集便是000~111每个数中1对应的数字所组成的集合,只需要将b数组从000变换到111共七次。具体代码如下:

#include<iostream>
#include<math.h>
#define MaxN 10
using namespace std;

//直接穷举法(根据二进制位求解,每次加1,输出1对应的数字)

void inc(int b[], int n) {		//将b表示的二进制数增1
	for (int i = 0; i < n; i++) {//遍历数组b
		if (b[i]) b[i] = 0;		//进位时,1变为0,继续对下一位进行进1
		else {
			b[i] = 1;			//0直接变成1
			break;
		}
	}
}

void PSet(int a[], int b[], int n) {
	int i, k;
	int pw = (int)pow(2, n);	//要进行2^n次方次
	cout << "1-" << n << "的幂集:" << endl;
	for (i = 0; i < pw; i++) {
		cout << "{";
		for (k = 0; k < n; k++) {//输出1对应的数字
			if (b[k]) {
				cout << a[k];
			}
		}
		cout << "} ";
		inc(b, n);
	}
}

int main() {
	int n = 3;
	int a[MaxN], b[MaxN];
	for (int i = 0; i < n; i++) {
		a[i] = i + 1;
		b[i] = 0;
	}
	PSet(a, b, n);
    return 0;
}

2、增量穷举法:即首先定义一个空集,和装所有幂集的大集合,每次向所有空集和有元素的集合中添加新的元素,并将添加后的集合放在大集合的后面,具体过程如下:

         具体代码如下:

#include<iostream>
#include<vector>
using namespace std;
vector<vector<int>> ps;
//增量穷举法

void Pset(int n) {
	vector<vector<int>> ps1;
	vector<vector<int>>::iterator it;
	vector<int> s;		//定义一个空集合并添加到ps中
	ps.push_back(s);
	for (int i = 1; i <= n; i++) {
		ps1 = ps;
		for (it = ps1.begin(); it != ps1.end(); ++it) {//将i添加到当前有的集合元素中
			(*it).push_back(i);
		}
		for (it = ps1.begin(); it != ps1.end(); ++it) {//将被添加的集合元素添加到ps中
			ps.push_back(*it);
		}
	}
}

void Dispps() {		//输出幂集
	vector<vector<int>>::iterator it;
	vector<int>::iterator sit;
	for (it = ps.begin(); it != ps.end(); ++it) {
		cout << "{";
		for (sit = (*it).begin(); sit != (*it).end(); ++sit) {
			cout << *sit;
		}
		cout << "} ";
	}
}

int main() {
	int n = 3;
	Pset(n);
	cout << "1-" << n << "的幂集:" << endl;
	Dispps();
	return 0;
}

简单0/1背包问题

一、问题描述:有n个重量分别为w1,w2,......,wn的物品(编号1~n),它们的价值分别为v1,v2,......vn,给定一个容量为W的背包。设计从这些物品中选取一部分物品放入该背包的方案,每个物品要么选中要么不选中(每个物品只能取0或1次),要求选中的物品不仅能够放到背包中,而且具有最大的价值。例:根据下表所示的4个物品求出W=6的所有解和最佳解。

二、问题求解:求所有解,先找问题所有解空间;求最佳解,在求所有解期间保存最佳解。此题解空间为四个物品所组成的全部集合(2^4=16个解),将每个集合的重量和价值加起来并保存在一个变量中,每次与最佳解相比较,看是否有更好的解。由此,可以仿照求解幂集问题,先使用二维数组按照物品编号组成集合,使用增量穷举法,将所有解空间存放在二维数组中,最后将其取出进行比较。具体代码如下:

#include<iostream>
#include<vector>
using namespace std;
vector<vector<int>> ps;		//幂集,存放所有子域

void PSet(int n) {			//按照物品的编号求出所有子域并添加到幂集中
	vector<vector<int>> ps1;
	vector<vector<int>>::iterator it;
	vector<int> s;
	ps.push_back(s);
	for (int i = 1; i <= n; i++) {//增量穷举法
		ps1 = ps;
		for (it = ps1.begin(); it != ps1.end(); ++it) {
			(*it).push_back(i);
		}
		for (it = ps1.begin(); it != ps1.end(); ++it) {
			ps.push_back(*it);
		}
	}
}

void KNap(int w[], int v[], int W) {
	int count = 0;						//第count求解方案
	int sumw, sumv;						//和重量,价值
	int maxi=1, maxw=0, maxv=0;				//最优解
	vector<vector<int>>::iterator it;	//幂集迭代器
	vector<int>::iterator sit;			//集合元素迭代器
	cout << " 序号\t选中物品\t总重量\t总价值\t能否装入" << endl;
	for (it = ps.begin(); it != ps.end(); ++it) {
		cout << count + 1 << "\t";
		sumw = sumv = 0;
		cout << "{";
		for (sit = (*it).begin(); sit != (*it).end(); ++sit) {//将集合中元素对应的重量和价值相加
			cout << *sit << " ";
			sumw += w[*sit - 1];
			sumv += v[*sit - 1];
		}
		if((*it).size()>=3) cout<< "}\t" << sumw << "\t" << sumv << "\t";
		else cout << "}\t\t" << sumw << "\t" << sumv << "\t";
		if (sumw <= W) {			//判断能否放进背包
			cout << "能" << endl;
			if (sumv > maxv) {		//判断是否具有更大价值
				maxi = count;
				maxw = sumw;
				maxv = sumv;
			}
		}
		else cout << "否" << endl;
		++count;
	}
	cout << "最佳方案为:";
	cout << "选中物品{ ";
	for (sit = ps[maxi].begin(); sit != ps[maxi].end(); ++sit) {
		cout << *sit << " ";
	}
	cout << "},";
	cout << "总重量:" << maxw << ",总价值:" << maxv << endl;
}

int main() {
	int n = 4, W = 6;
	int w[] = { 5,3,2,1 };
	int v[] = { 4,4,3,1 };
	PSet(n);
	cout << "0/1背包求解方案" << endl;
	KNap(w, v, W);
	return 0;
}

总结:增量穷举法。

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值