语言
Java
完全背包
题目
思路
动规五部曲思想与01背包类似,只是物品可以重复装进去了。
代码
//先遍历物品,再遍历背包
private static void testCompletePack(){
int[] weight = {1, 3, 4};
int[] value = {15, 20, 30};
int bagWeight = 4;
int[] dp = new int[bagWeight + 1];
for (int i = 0; i < weight.length; i++){ // 遍历物品
for (int j = weight[i]; j <= bagWeight; j++){ // 遍历背包容量
dp[j] = Math.max(dp[j], dp[j - weight[i]] + value[i]);
}
}
for (int maxValue : dp){
System.out.println(maxValue + " ");
}
}
//先遍历背包,再遍历物品
private static void testCompletePackAnotherWay(){
int[] weight = {1, 3, 4};
int[] value = {15, 20, 30};
int bagWeight = 4;
int[] dp = new int[bagWeight + 1];
for (int i = 1; i <= bagWeight; 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.println(maxValue + " ");
}
}
易错点
遍历顺序:遍历背包容量的时候,要从前开始遍历。
并且先遍历物品还是先遍历背包都可以。
518. 零钱兑换 II
题目
给你一个整数数组 coins 表示不同面额的硬币,另给一个整数 amount 表示总金额。
请你计算并返回可以凑成总金额的硬币组合数。如果任何硬币组合都无法凑出总金额,返回 0 。
假设每一种面额的硬币有无限个。
题目数据保证结果符合 32 位带符号整数。
思路
根据动规五部曲进行分析:
dp数组的含义:当j时,有多少种方法加起来等于amount。
递推公式:dp[j] += dp[j - coins[i]];
在背包中找最多方法都是这个递推公式。
初始化:dp[0] = 1;从零开始累加
遍历顺序:先物品再背包,且背包正序遍历
举例推导是否正确
代码
class Solution {
public int change(int amount, int[] coins) {
//可以把本题看做一个完全背包问题
//根据硬币金额凑出来总金额
int[] dp = new int[amount + 1];
dp[0] = 1;//初始化
for (int i = 0; i < coins.length; i++) {
for (int j = coins[i]; j <= amount; j++) {
//递推公式
dp[j] += dp[j - coins[i]];
}
}
return dp[amount];
}
}
易错点
本题只能先物品再背包,因为最后要获得的是一个组合,如果是先背包再物品会获得一个排列顺序。
377. 组合总和 Ⅳ
题目
给你一个由 不同 整数组成的数组 nums ,和一个目标整数 target 。请你从 nums 中找出并返回总和为 target 的元素组合的个数。
题目数据保证答案符合 32 位整数范围。
思路
与上题类似,不过本题需要求的相当于排列,上题求得算是组合。
根据动规五部曲进行分析:
dp数组的含义:当j时,有多少种方法加起来等于target。
递推公式:dp[i] += dp[i - coins[j]];
在背包中找最多方法都是这个递推公式。
初始化:dp[0] = 1;从零开始累加
遍历顺序:先背包再物品,且都是正序遍历
举例推导是否正确
代码
class Solution {
public int combinationSum4(int[] nums, int target) {
int[] dp = new int[target + 1];//dp数组的含义
dp[0] = 1;//初始化
for (int i = 0; i <= target; i++) {
for (int j = 0; j < nums.length; j++) {
if (i >= nums[j]) {
dp[i] += dp[i - nums[j]];
}
}
}
return dp[target];
}
}
易错点
本题是先遍历得背包容量。
70. 爬楼梯 (进阶)
题目
思路
之前做过类似的爬楼梯,是用贪心做的。本题用动规做。
根据动规五部曲进行分析:
dp数组的含义:当j时,有多少种方法加起来等于n。
递推公式:dp[j] += dp[j - i];
在背包中找最多方法都是这个递推公式。
初始化:dp[0] = 1;从零开始累加
遍历顺序:先背包再物品,且都是正序遍历
举例推导是否正确
代码
import java.util.Scanner;
class Main{
public static void main(String [] args){
Scanner sc = new Scanner(System.in);
int m, n;
while (sc.hasNextInt()) {
// 从键盘输入参数,中间用空格隔开
n = sc.nextInt();
m = sc.nextInt();
// 求排列问题,先遍历背包再遍历物品
int[] dp = new int[n + 1];
dp[0] = 1;
for (int j = 1; j <= n; j++) {
for (int i = 1; i <= m; i++) {
if (j - i >= 0) dp[j] += dp[j - i];
}
}
System.out.println(dp[n]);
}
}
}
易错点
本题采用得ACM模式了解先输入的是背包还是物品。
遍历顺序:因为他是排列问题所以先背包再物品。
总结
今天练了完全背包问题,明天继续动规问题。
加油!