题目来源
题目描述
class Solution {
public:
int backPackVIII(int n, vector<int> &value, vector<int> &amount){
}
};
题目解析
题目要求:1~n
这些数值中,有多少是可以用这些组成的组成的。相当于有容量为1~n
的背包,能装满的背包数量(不需要关心到底有几种方案能装满当前这个容量,只要求能装满)
硬币数量有限
多维背包
思路一
(1)定义状态:
- dp[i][j]:对于前i个硬币,是否能装满容量为j的背包
- i: 0 ~ m
- j: 0 ~ n
(2)转移方程
dp[i][j] = dp[i - 1][j - k * value[i - 1]], k: 0 ~ amount[i - 1]
(3)初始条件
- d p [ 0 ] [ j ] = f a l s e , j > 0 dp[0][j] = false, j > 0 dp[0][j]=false,j>0
- d p [ i ] [ 0 ] = t r u e dp[i][0] = true dp[i][0]=true
(4)答案
- c o u n t d p [ m ] [ j ] , j : 1 n count dp[m][j], j: 1 ~ n countdp[m][j],j:1 n
(5)时间复杂度
- 时间复杂度:O(n x m x k)
- 空间复杂度:O(n * m)
class Solution {
public:
int backPackVIII(int n, vector<int> &value, vector<int> &amount){
int len = value.size();
//dp[i][j]前i个硬币能否组成价值j
std::vector<std::vector<bool>> dp(len + 1, std::vector<bool>(n + 1));
for (int i = 0; i <= len; ++i) {
dp[i][0] = true;
}
for (int i = 1; i <= len; ++i) { // 硬币
int amt = amount[i - 1], val = value[i - 1];
for (int j = 1; j <= n; ++j) { //容量
for (int k = 1; k <= amt; ++k) { //件数
dp[i][j] = dp[i - 1][j];
if(j - val * k >= 0){
dp[i][j] = dp[i - 1][j] || dp[i - 1][j - val * k];
}
}
}
}
int result = 0;
for (int j = 1; j <= n; j++) {
if (dp[len][j]) {
result++; //题目要求1-n的j的个数
}
}
return result;
}
};
思路
(1)状态
- dp[i]表示coins是否可以组合成i的值。
class Solution {
public:
int backPackVIII(int n, vector<int> &value, vector<int> &amount){
std::vector<bool> dp(n + 1, false);
int len = value.size();
dp[0] = true;
for (int i = 1; i <= len; ++i) {
int amt = amount[i - 1], val = value[i - 1];
for (int j = 1; j <= amt; ++j) {
for (int k = n; k >= val; --k) {
if (!dp[k] && dp[k - value[i]]) { //记得!dp[k]可以剪枝
dp[k] = true;
}
}
}
}
int sum = 0;
for (int i = 1; i <= n; ++i) {
if (dp[i]) sum++;
}
return sum;
}
};
思路