代码随想录算法训练营第三十四天| 完全背包 518. 零钱兑换 II 377. 组合总和 Ⅳ
完全背包
区别:
每种物品都是可以无线多个
代码:
1 // 多背包问题 2 // 有N个物品,他们的体积和重量如下,但是这些物品有无限个 3 // 需要发挥背包的最大容量,来让价值最大 4 // 5 // dp[n]: 当容量为N的时候,背包的价值最大是多少 6 // dp[n]: 7 // dp[n] 8 // dp[n-weight[i]]+values[i] 9 // 10 // dp[0] = 0 11 // 12 int test_CompletePack(vector<int>& weight, vector<int>& value, int& bagWeight) 13 { 14 vector<int> dp(bagWeight + 1, 0); 15 16 for (int i = 0; i < weight.size(); i++) 17 { 18 for (int j = weight[i]; j <= bagWeight; j++) 19 { 20 dp[j] = max(dp[j], value[i] + dp[j - weight[i]]); 21 } 22 } 23 24 return dp[bagWeight]; 25 }
518. 零钱兑换 II
难点——多少种方法再深入思考:
1 // dp[n] : 当容量为N 时,它的组合数 2 // 3 // 重要的问题:不是 dp[j] = 1+dp[j-nums[i]] 得到满足J时有多少种方法 4 // 它的含义是 满足J时,它的最大子集数是多少 5 // 6 // 多少种方法 dp[5]: dp[1]+4, dp[2]+3 其实共有 dp[1]+dp[2]这几种方法 7 // 8 // 初始化的时候需要为dp[0]=1
所以只要遇到 需要多少种方法的时候都要用
dp[j]+=dp[j-nums[i]];
代码:
1 // 要求:有这几个面值,需要组合这些面值和为目标值 2 // 3 // 思路:物品的weight value都是coins 4 // 5 // dp[n] : 当容量为N 时,它的组合数 6 // 7 // 重要的问题:不是 dp[j] = 1+dp[j-nums[i]] 得到满足J时有多少种方法 8 // 它的含义是 满足J时,它的最大子集数是多少 9 // 10 // 多少种方法 dp[5]: dp[1]+4, dp[2]+3 其实共有 dp[1]+dp[2]这几种方法 11 // 12 // 初始化的时候需要为dp[0]=1 13 // 14 // 15 int change(int amount, vector<int>& coins) { 16 17 vector<int> dp(amount + 1, 0); 18 19 20 dp[0] = 1; 21 for (int i = 0; i < coins.size(); i++) 22 { 23 for (int j = coins[i]; j <= amount; j++) 24 { 25 dp[j] += dp[j - coins[i]]; 26 } 27 } 28 29 30 return dp[amount]; 31 }
377. 组合总和 Ⅳ
区别:
这个是排列问题
需要先遍历背包,再遍历物品
因为会有超出范围的警告,所以需要dp[j]<INT_MAX- dp[j - nums[i]]
代码:
1 // 要求:不同整数,返回总和为target的组合个数 2 // 难点:里面的数字的个数是无限多 3 // 4 // 完全背包问题: 5 // 6 // dp[n]:当总和为N时,组合个数 7 // 8 // dp[j] += dp[j-nums[i]]; 9 // 10 int combinationSum4(vector<int>& nums, int target) { 11 vector<int> dp(target + 1, 0); 12 13 dp[0] = 1; 14 15 for (int j = 0; j <= target; j++) 16 { 17 for (int i = 0; i < nums.size(); i++) 18 { 19 if (j >= nums[i] && dp[j]<INT_MAX- dp[j - nums[i]]) 20 dp[j] += dp[j - nums[i]]; 21 } 22 } 23 24 25 return dp[target]; 26 }