完全背包理论基础
1. 有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],价值是value[i] 。每件物品都有无限个(即可以放入背包多次),求解将哪些物品装入背包里物品价值总和最大。
2. 「完全背包」与「01背包」唯一的不同:遍历顺序。01背包的内循环从大到小遍历,为了保证每个物品仅被添加一次;完全背包的物品可以添加多次,因此从小到大遍历;01背包中,二维dp数组的两个for遍历的先后循序可以颠倒,一维dp数组的两个for循环先后循序一定是先物品,再背包容量。完全背包中,一维dp数组的两个for循环嵌套顺序可以颠倒。
//先遍历物品,再遍历背包容量
public static void testCompletePack(){
int[] weight = {1,3,4};
int[] value = {15,20,30};
int bagSize = 4;
int[] dp = new int[bagSize+1];
for (int i = 0; i < weight.length; i++) {
for (int j = weight[i]; j <= bagSize; j++) {
dp[j] = Math.max(dp[j],dp[j-weight[i]]+value[i]);
}
}
for(int maxValue:dp){
System.out.print(maxValue+" ");
}
}
public static void testCompletePack() {
int[] weight = {1, 3, 4};
int[] value = {15, 20, 30};
int bagSize = 4;
int[] dp = new int[bagSize + 1];
for (int i = 1; i <= bagSize; i++) {
for (int j = 0; j < weight.length; j++) {
if(i-weight[j]>0){
dp[i] = Math.max(dp[i], dp[i - weight[j]] + value[j]);
}
}
}
for (int maxValue : dp) {
System.out.print(maxValue + " ");
}
}
力扣
1. 本题区别于纯完全背包问题之处:纯完全背包求凑成背包最大价值,本题求凑成总金额的物品组合个数。
2. dp数组以及下标的含义:dp[j]表示凑成总金额为j的货币组合个数为dp[j]。
3. 递推公式:dp[j]就是所有的dp[j-coins[i]]相加。因此,dp[j] += dp[j-coins[i]]。
4. 初始化:dp[0] = 1(递推公式的基础),其他下标的dp初始化为0。
5. 遍历顺序:外层for循环遍历物品(钱币),内层for遍历背包(金钱总额),得到的dp[j]为组合数;假如先外层for循环遍历背包(金钱总额),内层for循环遍历物品(钱币),得到的dp[j]就是排列数;因此,外层遍历物品(钱币),内层遍历背包(金钱总额)。
class Solution {
public int change(int amount, int[] coins) {
int[] dp = new int[amount+1];
dp[0]=1;
for(int i=0;i
力扣
1. 本题求凑成target的排列个数。类似上一题,区别在于上一题求组合个数,本题求排列个数;
2. dp数组及其下标含义:dp[i]表示凑成目标正整数为i的排列个数为dp[i];
3. 递推公式:dp[i] += dp[i-nums[j]];
4. 初始化:dp[0] = 1(递推公式的基础),其他下标的dp初始化为0;
5. 遍历顺序:外层for循环遍历背包(目标正整数),内层for循环遍历物品(数字)。
class Solution {
public int combinationSum4(int[] nums, int target) {
int[] dp = new int[target+1];
dp[0] = 1;
for(int i=0;i<=target;i++){
for(int j=0;j=nums[j]){
dp[i] += dp[i-nums[j]];
}
}
}
return dp[target];
}
}
求装满背包有几种方法,递归公式类似(+=),关键在于遍历顺序。如果求的是组合个数,外层for循环遍历物品,内层for循环遍历背包容量;如果求的是排列个数,外层for循环遍历背包容量,内层for循环遍历物品。