完全背包问题是另一种背包问题,与0-1背包问题相似,但有一个重要区别:在完全背包问题中,每种物品可以选择多次放入背包,而不像0-1背包问题中一种物品只能选择一次。
解决完全背包问题通常仍然使用动态规划。以下是解决完全背包问题的基本步骤:
1.定义状态:创建一个二维数组dp,其中dp[i][j] 表示在前i种物品中,背包容量为j时的最大总价值。这个数组的行表示物品的种类,列表示背包容量。
2.状态转移方程:状态转移方程也与0-1背包问题类似,但有一个重要区别,即在选择第i种物品时,可以多次选择,因此需要考虑多种选择情况。状态转移方程为:
3.dp[i][j] = max(dp[i-1][j], dp[i][j - weight[i]] + value[i]),其中weight[i] 是第i种物品的重量,value[i] 是第i种物品的价值。
4.初始化:初始化dp数组的第一行和第一列,通常为0,表示没有物品或背包容量为0时的最大总价值。
5.填充DP表格:按照状态转移方程,从左上角向右下角逐步填充dp数组。
6.最终结果:dp[n][capacity] 就是在n种物品中,背包容量为capacity时的最大总价值,其中n是物品的种类。
public class KnapsackProblemComplete {
static class Item {
//索引
int index;
//重量
int weight;
//价值
int value;
//名字
String name;
public Item(int index, int weight, int value, String name) {
this.index = index;
this.weight = weight;
this.value = value;
this.name = name;
}
public String toString() {
return "Item(" +
"index=" + index +
')';
}
}
public static void main(String[] args) {
Item[] items = {
new Item(1, 2, 3, "青铜"), //c
new Item(2, 3, 4, "白银"), //s
new Item(3, 4, 7, "黄金"), //a
};
System.out.println(select(items, 6));
System.out.println();
}
/**
* 0 1 2 3 4 5 6
* 1 0 0 c c cc cc ccc
* 2 0 0 c s cc sc ccc
* 3 0 0 c a a a ac
*
* if(放得下){
* d[i][j] = max(dp[i-1][j],dp[i][j-item.weight]+item.value)
* }else{
* dp[i][j] = dp[i-1][j]
* }
*/
private static int select(Item[] items, int total) {
int[][] dp = new int[items.length][total + 1];
Item item0 = items[0];
for (int j = 0; j < total + 1; j++) {
if (j >= item0.weight) {
dp[0][j] = dp[0][j - item0.weight] + item0.value;
}
}
print(dp);
for (int i = 1; i < items.length; i++) {
for (int j = 0; j < total+1; j++) {
Item item = items[i];
int x = dp[i - 1][j]; //上次的最大价值
if(j >= item.weight){ //放得下
// 剩余空间能装的最大价值 + 当前物品价值
dp[i][j] = Integer.max(x,dp[i][j-item.weight]+item.value);
}else { //放不下
dp[i][j] = x;
}
}
print(dp);
}
return dp[items.length-1][total];
}
static void print(int[][] dp){
for (int i = 0; i < dp.length; i++) {
System.out.println(Arrays.toString(dp[i]));
}
System.out.println("-----------------------");
}
}