01背包问题
1、问题描述:
有n个物品,它们有各自的体积和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和?
为描述方便,首先定义如下变量:
Vi:表示第 i 个物品的价值;
Wi:表示第 i 个物品的体积;
V(i, j):表示当前背包容量为j时,前 i 个物品最佳组合对应的价值。
2、解题思路:
1、建立模型,即求max(V1X1 + V2X2 + … + VnXn);(背包问题抽象化(X1,X2,…,Xn,其中 Xi 取0或1,表示第 i 个物品不选或选)
2、寻找约束条件,W1X1+W2X2+…+WnXn < capacity;
3、寻找递推关系式,面对当前商品有两种可能性:
- 包的当前容量小于当前商品体积时,当前商品装不下,此时的价值与前i-1个的价值是一样的,即
V(i, j) = V(i-1, j)
; - 包的当前容量大于或等于当前商品体积时,还有足够的容量可以装当前商品,但装了也不一定达到当前最优价值,所以在装与不装之间选择最优的一个,即
V(i, j)=max{V(i-1, j),V(i-1, j-w(i))+v(i)}
。其中V(i-1, j)
表示不装,V(i-1, j-w(i))+v(i)
表示装了第i个商品,在比当前背包容量减少w(i)
时的结果上V(i-1, j-w(i))
)价值增加了v(i);
3、递推关系式
- 当 j < w(i) 时: V(i, j) = V(i-1, j)
- 当 j >= w(i)时:V(i, j) = max{V(i-1, j),V(i-1, j-w(i))+v(i)}
4、输出最优解
通过上面的方法可以求出背包问题的最优解,但还不知道这个最优解由哪些商品组成,故要根据最优解回溯找出解的组成,根据填表的原理可以有如下的寻解方式:
V(i, j) = V(i-1, j)
时,说明没有选择第i
个商品,则回到V(i-1, j)
;
V(i, j) = V(i-1, j-W(i)) + V(i)
时,说明装了第i个商品,该商品是最优解组成的一部分
,随后我们得回到装该商品之前,即回到V(i-1, j-w(i))
;
一直遍历到i=0
结束为止,所有解的组成都会找到。
5、01背包问题代码
#include <iostream>
#include <vector>
using namespace std;
int Max(int x, int y) {
return x > y ? x : y;
}
void PrintOptimal(vector<vector<int>> &dp, vector