求解简单0/1背包问题
【问题描述】有n个重量分别为w1、w2、...wn的物品(物品编号为1~n),它们的价值分别为v1、v2、...vn,给定一个容量为W的背包。设计从这些物品中选取一部分物品放入该背包的方案,每个物品要么选中要么不选中,要求选中的物品不仅能够放到背包中,而且具有最大价值,并对下表所示的四个物品求出W=6时的所有解和最佳解。
物品编号 | 重量 | 价值 |
1 | 5 | 4 |
2 | 3 | 4 |
3 | 2 | 3 |
4 | 1 | 1 |
【问题求解】对于n个物品、容量为W的背包问题,采用求幂集的方法求出所有的物品组合,对于每一种组合,计算其总重量sumw和总价值sumv,当sumw小于等于W时该组合是一种解,并通过比较将最佳方案保存到maxsumw和maxsumv中,最后输出所有的解和最佳解。
源程序如下:
#include <iostream>
#include <vector>
using namespace std;
//求1-n的幂集
vector<vector<int> >ps;
void PSet(int n) {
vector<vector<int> >ps1;
vector<int> s;
ps.push_back(s);
vector < vector<int>>::iterator it;
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 = 1; //方案编号
int sumw, sumv; //当前方案的总重量和总价值
int maxi, maxsumw = 0, maxsumv = 0; //最佳方案的编号、总重量和总价值
vector<vector<int> >::iterator it; //幂集迭代器
vector<int>::iterator its; //幂集集合元素迭代器
cout << "编号" <<"\t"<< "选中物品" << "\t" << "总重量" << "\t" << "总价值" << "\t" << "能否装入" << endl;
for (it = ps.begin(); it != ps.end();++it) { //扫描ps中的每一个集合元素
cout << count << "\t";
sumw = 0, sumv = 0;
cout << "{";
for (its = (*it).begin(); its != (*it).end();++its) {
cout << (*its);
sumw += w[*its-1]; //w数组下标从0开始
sumv += v[*its - 1]; //v数组下标从0开始
}
cout << "}"<<"\t\t";
cout << sumw << "\t" << sumv << "\t";
if (sumw<=W) {
cout << "能"<<endl;
if (sumv> maxsumv) { //比较求最优方案
maxsumv = sumv;
maxsumw = sumw;
maxi = count;
}
}
else {
cout << "不能"<<endl;
}
count++; //方案编号增加1
}
cout << endl;
cout << "最佳方案为";
cout << "选中物品";
cout << "{";
for (its = ps[maxi].begin(); its != ps[maxi].end();++its) {
cout << *its;
}
cout << "}";
cout << "总重量为" << maxsumw << "," << "总价值为:" << maxsumv << 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);
system("pause");
return 0;
}
输出结果为:
0/1背包的求解方案为:
编号 选中物品 总重量 总价值 能否装入
1 {} 0 0 能
2 {1} 5 4 能
3 {2} 3 4 能
4 {12} 8 8 不能
5 {3} 2 3 能
6 {13} 7 7 不能
7 {23} 5 7 能
8 {123} 10 11 不能
9 {4} 1 1 能
10 {14} 6 5 能
11 {24} 4 5 能
12 {124} 9 9 不能
13 {34} 3 4 能
14 {134} 8 8 不能
15 {234} 6 8 能
16 {1234} 11 12 不能
最佳方案为选中物品{1234}总重量为6,总价值为:8
请按任意键继续. . .
【算法分析】对于n个物品,最主要的时间话费在求幂集上,所以算法的时间复杂度为O()。