完全背包相比于0、1背包最大的区别就是每个物品的数量不限。原始的完全背包问题为:在每个物品数量不限的情况下,背包能容纳的最大物品价值。常见的变体有求选取物品的组合数和排列数(装满背包有几种方法),这时候先遍历物品还是先遍历容量就有很大的讲究
- 先遍历物品,物品是顺序遍历的,放入结果的顺序一定,所以此时求得是组合数(较少的)
- 先遍历背包,意味着物品会多次被遍历,所以物品放入的顺序实际上是一种排列,所以此时求的是排列数(较多)
下面以Leetcode 518. 零钱兑换 II 举例,有需要自行跳转到Leetcode查看题目。
下面的代码进行了扩展,能输出解决方案,这里你可以方便的实验,将for循环调整一下顺序,可以看到打印的输出有什么不同
class Solution {
public:
int change(int amount, vector<int>& coins) {
using PathList = vector<vector<int>>;
int n = coins.size();
// dp[j]表示填满大小为j的背包的组合数
vector<int>dp(amount + 1, 0);
// dp[j] = dp[j] + dp[j-coins[i]];
dp[0] = 1;
vector<PathList> path(amount + 1);
path[0].push_back({});
for(int i = 0; i < n; i++){
for(int j = coins[i]; j <= amount; j++){
// dp[j] += dp[j-coins[i]];
dp[j] = dp[j] + dp[j-coins[i]]; // 当前方案dp[j] + 方案[j-coins[i]].push_back(coins[i])
PathList prev = path[j-coins[i]];
for(auto & path : prev){
path.push_back(coins[i]);
}
path[j].insert(path[j].end(), prev.begin(), prev.end());
}
}
int i = 0;
for(auto& L : path.back()){
for(auto ele : L){
cout << ele << "+";
}
cout << "\b=" << amount << endl;
}
return dp[amount];
}
};
1096

被折叠的 条评论
为什么被折叠?



