diff --git a/problems/0377-组合总和IV(完全背包的排列问题二维迭代理解).md b/problems/0377-组合总和IV(完全背包的排列问题二维迭代理解).md new file mode 100644 index 00000000..276329c5 --- /dev/null +++ b/problems/0377-组合总和IV(完全背包的排列问题二维迭代理解).md @@ -0,0 +1,145 @@ +# 完全背包的排列问题模拟 + +#### Problem + +1. 排列问题是完全背包中十分棘手的问题。 +2. 其在迭代过程中需要先迭代背包容量,再迭代物品个数,使得其在代码理解上较难入手。 + +#### Contribution + +本文档以力扣上[组合总和IV](https://leetcode.cn/problems/combination-sum-iv/)为例,提供一个二维dp的代码例子,并提供模拟过程以便于理解 + +#### Code + +```cpp +int combinationSum4(vector& nums, int target) { + // 定义背包容量为target,物品个数为nums.size()的dp数组 + // dp[i][j]表示将第0-i个物品添加入排列中,和为j的排列方式 + vector> dp (nums.size(), vector(target+1,0)); + + // 表示有0,1,...,n个物品可选择的情况下,和为0的选择方法为1:什么都不取 + for(int i = 0; i < nums.size(); i++) dp[i][0] = 1; + + // 必须按列遍历,因为右边数组需要知道左边数组最低部的信息(排列问题) + // 后面的模拟可以更清楚的表现这么操作的原因 + for(int i = 1; i <= target; i++){ + for(int j = 0; j < nums.size(); j++){ + // 只有nums[j]可以取的情况 + if(j == 0){ + if(nums[j] > i) dp[j][i] = 0; + // 如果背包容量放不下 那么此时没有排列方式 + else dp[j][i] = dp[nums.size()-1][i-nums[j]]; + // 如果背包容量放的下 全排列方式为dp[最底层][容量-该物品容量]排列方式后面放一个nums[j] + } + // 有多个nums数可以取 + else{ + // 如果背包容量放不下 那么沿用0-j-1个物品的排列方式 + if(nums[j] > i) dp[j][i] = dp[j-1][i]; + // 如果背包容量放得下 在dp[最底层][容量-该物品容量]排列方式后面放一个nums[j]后面放个nums[j] + // INT_MAX避免溢出 + else if(i >= nums[j] && dp[j-1][i] < INT_MAX - dp[nums.size()-1][i-nums[j]]) + dp[j][i] = dp[j-1][i] + dp[nums.size()-1][i-nums[j]]; + } + } + } + // 打印dp数组 + for(int i = 0; i < nums.size(); i++){ + for(int j = 0; j <= target; j++){ + cout<