1.定义
有N件物品和一个容量为V的背包。第i件物品的重量是w[i],价值是v[i]。求解将哪些物品装入背包可使这些物品的重量总和不超过背包容量,且价值总和最大。
2.01背包问题
说明:
在解决问题之前,为描述方便,首先定义一些变量:Vi表示第 i 个物品的价值,Wi表示第 i 个物品的体积,定义V(i,j):当前背包容量 j,前 i 个物品最佳组合对应的价值,同时背包问题抽象化(X1,X2,…,Xn,其中 Xi 取0或1,表示第 i 个物品选或不选)。
1、建立模型,即求max(V1X1+V2X2+…+VnXn);
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);
由此可以得出递推关系式:
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)}
这里需要解释一下,为什么能装的情况下,需要这样求解(这才是本问题的关键所在!):
可以这么理解,如果要到达V(i,j)这一个状态有几种方式?
肯定是两种,第一种是第i件商品没有装进去,第二种是第i件商品装进去了。没有装进去很好理解,就是V(i-1,j);装进去了怎么理解呢?如果装进去第i件商品,那么装入之前是什么状态,肯定是V(i-1,j-w(i))。由于最优性原理(上文讲到),V(i-1,j-w(i))就是前面决策造成的一种状态,后面的决策就要构成最优策略。两种情况进行比较,得出最优。
解决代码:
/**
* 01-背包
*
* @param capacity 背包容量
* @param weight 物品重量数组
* @param value 物品价值数组
*/
public int bagProblem(int capacity, int[] weight, int[] value) {
int row = weight.length;
int[][] arr = new int[row + 1][capacity + 1];
for (int i = 1; i <= row; i++) {
for (int j = 1; j <= capacity; j++) {
if (j < weight[i - 1]) {
arr[i][j] = arr[i - 1][j];
} else {
arr[i][j] = Math.max(arr[i - 1][j], arr[i - 1][j - weight[i - 1]] + value[i - 1]);
}
}
}
print(arr);
return arr[row][capacity];
}
public void print(int[][] arr) {
for (int[] ints : arr) {
for (int j = 0; j < arr[0].length; j++) {
System.out.print(ints[j] + "\t");
}
System.out.println();
}
}
结果显示:
3.完全背包问题
解决代码:
/**
* 完全背包
*
* @param capacity 背包容量
* @param weight 物品重量数组
* @param value 物品价值数组
*/
public int bagProblems(int capacity, int[] weight, int[] value) {
int[] arr = new int[capacity + 1];
for (int i = 0; i < weight.length; i++) {
for (int j = weight[i]; j <= capacity; j++) {
arr[j] = Math.max(arr[j], arr[j - weight[i]] + value[i]);
}
}
return arr[capacity];
}
结果显示:
4.总代码
package practice;
/**
* 背包问题01
*/
public class Knapsack {
public static void main(String[] args) {
int[] weight = {1, 2, 4};
int[] value = {15, 35, 45};
Knapsack knapsack = new Knapsack();
System.out.println(knapsack.bagProblems(4, weight, value));
}
/**
* 01-背包
*
* @param capacity 背包容量
* @param weight 物品重量数组
* @param value 物品价值数组
*/
public int bagProblem(int capacity, int[] weight, int[] value) {
int row = weight.length;
int[][] arr = new int[row + 1][capacity + 1];
for (int i = 1; i <= row; i++) {
for (int j = 1; j <= capacity; j++) {
if (j < weight[i - 1]) {
arr[i][j] = arr[i - 1][j];
} else {
arr[i][j] = Math.max(arr[i - 1][j], arr[i - 1][j - weight[i - 1]] + value[i - 1]);
}
}
}
print(arr);
return arr[row][capacity];
}
/**
* 完全背包
*
* @param capacity 背包容量
* @param weight 物品重量数组
* @param value 物品价值数组
*/
public int bagProblems(int capacity, int[] weight, int[] value) {
int[] arr = new int[capacity + 1];
for (int i = 0; i < weight.length; i++) {
for (int j = weight[i]; j <= capacity; j++) {
arr[j] = Math.max(arr[j], arr[j - weight[i]] + value[i]);
}
}
return arr[capacity];
}
public void print(int[][] arr) {
for (int[] ints : arr) {
for (int j = 0; j < arr[0].length; j++) {
System.out.print(ints[j] + "\t");
}
System.out.println();
}
}
}
背包问题的解答就到此结束啦!如果你有任何问题可以再评论区留言,我会一一解答哦!