问题描述
- 有n个物品,第i个物品价值为vi,重量为wi,其中vi和wi均为非负数,背包的容量为W,W为非负数。现需要考虑如何选择装入背包的物品,使装入背包的物品总价值最大。
问题分析
- 在选择装入背包的物品时,对每种物品i只有两种选择,装入或者不装入。
- 假设前i种物品放入容量为j的背包中的最优值为m[i][j],则
m[i][j] = max{m[i-1][j-wi]+vi, m[i-1][j]}, 当 j>= wi
m[i][j] = m[i-1][j], 当 j< wi
实现如下
public class ZeroOneBag {
public static void zeroOneBagMax(int[] v, int[] w, int c, int n)
{
int[][] m = new int[n][c+1];
for(int i = 0; i < n; i++)
m[i][0] = 0;
for(int i = 0; i <= c; i++)
{
if(i < w[0])
m[0][i] = 0;
else
m[0][i] = v[0];
}
for(int i = 1; i < n; i++)
{
int jMax = Math.min(c, w[i]-1);
for(int j = 0; j <= jMax; j++){
m[i][j] = m[i-1][j];
}
for(int j = w[i]; j <= c; j++){
m[i][j] = Math.max(m[i-1][j-w[i]] +v[i], m[i-1][j]);
}
}
System.out.println(m[n-1][c]);
}
public static void main(String[] args) {
// TODO Auto-generated method stub
int[] v = new int[]{6,3,5,4,6};//{0, 60, 100, 120};
int[] w = new int[]{2,2,6,5,4};//{0, 10, 20, 30};
int c = 10;
zeroOneBagMax(v, w, c,w.length);
}
}
总结
- 与0-1背包问题类似的问题有:1.子数组和接近某个值的问题,因为该值可以作为0-1背包中的容量c。2.将数组分成和最为接近的两个子数组。其实本质就是求一个子数组,其和最接近sum/2。
关于子数组方面的拓展 - 1.最大子数组问题
- 2.零子数组问题
- 3.两个不相交的连续子数组和的最大值