背包问题
一个旅行者随身携带一个背包。可以放入背包的物品有n种,每种物品的重量和价值分别为wi, vi如果背包的最大重量限制是b,每种物品可以放多个.怎样选择放入背包的物品以使得背包的价值最大?不妨设上述wi,vi, b都是正整数.
1、问题建模
目标函数 {v1x1 + v2x2 + …+ vnxn}max
约束条件 wixi <= b
2、子问题界定
3、优化函数的递推方程
老师这里的第一个递推方程应该不对,题目是每个物品可以装n种,而不是一种;
所以Fk(y) = max{ Fk-1(y),Fk(y-nwk) + nvk } n是装入第k个物品的数量
当y-nwk<0时,Fk(y-nwk)取负无穷大;
4、界定最小子问题
当k=0是,所有的F0(y)都等于0;
当k=1时,问题最小,此时F1(y) = y/w1向下取整 * v1;
5、明确计算顺序
k=1, y= 1 2 3 … y
k=2, y= 1 2 3 … y
.
.
.
k=k,y= 1 2 3 … y
6、保存问题结果
m[k] [y] = 装入前k个物品最大限重y时,最大价值
7、标记函数
s[k] [y] = 装入前k个物品最大限重y时,最大价值时,装入的第k个物品的数量
标记函数的取值与老师不一样
老师标记的是最大标号
一个问题实例的解过程
0-1背包问题用这节课老师讲的递推方程很好解,复杂度很低,老师这节课讲的问题更像一个0-1背包问题
F(k,y) = max{F(k-1,y),F(k,y-wk)+vk};
多背包问题如果没有物品的限制,更像是可以一个个背包问题求解取得最大值再合并
二位背包限制条件增加一种,可能需要多增加一层遍历
子问题F(k,b,v) 也就是装入前k种物品,重量不超过b,体积不超过v;
递推方程F(k,b,v) = F(k-1,b-nbk,v-nvk) + nVk(值n倍的第k个物品的价值)
java代码实现
//背包问题
//问题描述:一个背包,可以放入背包的物品有n种,每种物品的重量和价值分别为wi,vi,如果背包的最大重量限制是b,每种物品可以放多个,
//怎样选择放入背包的物品使得背包的价值最大
public void knapsackProblem(int n, int b, int[] w, int[] v) {
int[][] m = new int[n+1][b+1];
int[][] s = new int[n+1][b+1];
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= b; j++) {
for (int k = 0; k <= j/w[i-1]; k++) {
int temp = m[i-1][j-k*w[i-1]] + k*v[i-1];
if(temp > m[i][j]) {
m[i][j] = temp;
s[i][j] = k;
}
}
}
}
getKnapsackProblem(n, b, m, s, w, v);
}
private void getKnapsackProblem(int n, int b, int[][] m, int[][] s, int[] w, int[] v) {
System.out.println("当背包只装入前" + n + "个物品,装入最大重量为" + b + "时,能装入的最大价值是" + m[n][b] + ", 装入第" + n + "个物品的数量是" + s[n][b]);
if(n == 0 || b == 0) {
return;
}
getKnapsackProblem(n-1, b-s[n][b]*w[n-1], m, s, w, v);
}