参考:0-1背包问题 —— 四种解法解题
0-1背包问题
有n个物品,它们有各自的体积和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和?
分别用蛮力法、动态规划法、回溯法求解0/1背包问题。
输入:
3 10
5 8
8 20
4 17
输出:
1 3
25
编译:g++ -o test1 test1.cpp
执行:把数据放到 input.txt 中,就不需要每次都输数据了
Get-Content input.txt | .\test1.exe
/*******综合练习*******************
* 用sort函数对自定义的类进行排序
* 快速排序
* 0-1背包问题:
* 暴力搜索(深度优先)
* 动态规划
* 回溯法
***********************************/
#include <iostream>
#include <vector>
#include <algorithm>
#include <cmath>
using namespace std;
class goods {
public:
int w;
int v;
int sign;//编号
goods(int sign,int w, int v) {
this->w = w;
this->v = v;
this->sign = sign;
}
};
vector<goods> goo;
int N, C;//物品数量,背包容量
int bestValue, currValue, currWeigh;//最大价值,当前价值,当前重量
int X[100], currX[100];//最终存储状态,当前存储状态
bool cmpless(const goods& s1, const goods& s2);
int getstandard(vector<goods> &goo, int i, int j);
void quicksort(vector<goods> &goo, int begin, int end);//快排
void Force(int i);//暴力法
int DynamicPlan();//动态规划
void back(int i);
void BackTrack();//回溯法
int main()
{
cin >> N >> C;//物品种类和背包容量
for (int i = 0, w, v;i < N;i++) {
cin >> w >> v;
goo.push_back(goods(i+1,w, v));
}
/*自己试试用sort排序*/
/*
sort(goo.begin(), goo.end(), cmpless);
for (int i = 0;i < N;i++) {
cout << i << " " << goo[i].w << " " << goo[i].v << endl;;
}*/
/*自己试着写快排*/
/*
quicksort(goo, 0, N - 1);
for (int i = 0;i < N;i++) {
cout << goo[i].sign << " " << goo[i].w << " " << goo[i].v << endl;;
}*/
//Force(0);//暴力搜索,深度优先
//bestValue = DynamicPlan();//动态规划
BackTrack();
for (int i = 0;i < N;i++) {
if(X[i]==1)
cout << i+1 << " ";
}
cout << endl;
cout << bestValue << endl;
return 0;
}
void BackTrack() {
//回溯法
memset(X, 0, sizeof(X));
sort(goo.begin(), goo.end(), cmpless);//将物品按单位重量价值降序排列
back(0);
return;
}
void back(int i) {
if (i > N - 1) {
//结束条件
//搜索到最深处,判断是否符合要求
if (bestValue < currValue) {
for (int k = 0;k < N;k++) {
X[k] = currX[k];//存储更优的路径
}
bestValue = currValue;
}
return;
}
if (currWeigh + goo[i].w <= C) {
//对每一步探测进行评估
//进入左子树
currWeigh += goo[i].w;
currValue += goo[i].v;
currX[i] = 1;//装入背包
Force(i + 1);
currWeigh -= goo[i].w;
currValue -= goo[i].v;//回溯,进入右子树
}
currX[i] = 0;
back(i + 1);
return;
}
int DynamicPlan() {
//动态规划
//时间复杂度 n*C
int V[100][10 * 100];
for (int i = 0;i < N;i++) {
V[i][0] = 0;
//初始化第0列,当背包容量为0时,前j件物品能装到背包的最大价值V[j][0]=0;
}
for (int j = 0;j < C;j++){
V[0][j] = 0;
//初始化第0行,当不放物品时能装到背包中的最大价值为0;
}
for (int i = 1;i <= N;i++) {
for (int j = 1;j <= C;j++) {
/* V(i,j)=V(i-1,j) j<wi *
* max{V(i-1,j),V(i-1,j-wi)+vi} j>=wi */
if (j < goo[i - 1].w) {
V[i][j] = V[i - 1][j];
}
else {
V[i][j] = max(V[i - 1][j], V[i - 1][j - goo[i - 1].w] + goo[i - 1].v);
}
}
}
for (int i = N, j = C;i > 0;i--) {
if (V[i][j] > V[i - 1][j]) {
X[i - 1] = 1;
j = j - goo[i - 1].w;
}
else
X[i - 1] = 0;
}
return V[N][C];
}
void Force(int i) {
//暴力法
//安排第i个物品
//递归,深度优先搜索
//时间复杂度2^n
if (i > N - 1) {
//搜索到最深处,判断是否符合要求
if (bestValue < currValue&&currWeigh <= C) {
for (int k = 0;k < N;k++) {
X[k] = currX[k];//存储更优的路径
}
bestValue = currValue;
}
return ;
}
currWeigh += goo[i].w;
currValue += goo[i].v;
currX[i] = 1;//装入背包
Force(i + 1);
currWeigh -= goo[i].w;
currValue -= goo[i].v;
currX[i] = 0;
Force(i + 1);
return;
}
bool cmpless(const goods& s1, const goods& s2) {
return (1.0*s1.v)/s1.w > (1.0*s2.v)/s2.w;
}
int getstandard(vector<goods> &goo, int i, int j) {
goods key = goo[i];
while (i < j) {
while (i < j && !cmpless(goo[j], key)) {
j--;
}
if (i < j) {
goo[i] = goo[j];
}
while (i < j && !cmpless(key, goo[i])) {
i++;
}
if (i < j) {
goo[j] = goo[i];
}
}
goo[i] = key;
return i;
}
void quicksort(vector<goods> &goo, int begin, int end) {
if (begin < end) {
int standard = getstandard(goo, begin, end);
quicksort(goo, begin, standard - 1);
quicksort(goo, standard + 1, end);
}
}