//dp[j] 总价值为j的背包有多少种组合
//dp[j]=dp[j-coins[i]] 面额为coins[i]的硬币可以用,那么满足价值为j-coins[i]的背包此时也十满足价值j的一种情况所以累加
//dp[0]=1
class Solution {
public:
int change(int amount, vector<int>& coins) {
vector<int> dp(amount+1, 0);
dp[0]=1;
for (int i=0; i<coins.size(); i++){
for (int j=coins[i]; j<amount+1; j++){
dp[j]+=dp[j-coins[i]];
}
}
return dp[amount];
}
};
57. 爬楼梯
# include <iostream>
# include <vector>
using namespace std;
int main(){
int high, stepRange;
cin >> high >>stepRange;
vector<int> dp(high+1, 0);
dp[0]=1;
for (int j=0; j<high+1; j++){
for (int i=1; i<stepRange+1; i++){
if (j>=i) dp[j]+=dp[j-i];
}
}
cout << dp[high];
}
针对物品的排列,先遍历背包再遍历物品。对于一个固定价值的背包,用各种物品去填满它。
针对背包的组合,先遍历物品再遍历背包。就是尝试用不同个数不同价值的物品填满总价为j的背包。
322. 零钱兑换
如果求组合数就是外层for循环遍历物品,内层for遍历背包。
如果求排列数就是外层for遍历背包,内层for循环遍历物品。
//组合题,先遍历物品
//dp[j] 价值j的背包最少硬币数方案所需的硬币个数
//dp[j]=min(dp[j], dp[j-coin[i]])
//dp[0]=1
class Solution {
public:
int coinChange(vector<int>& coins, int amount) {
vector<int> dp(amount+1, INT_MAX);
dp[0]=0;
for (int i=0; i<coins.size(); i++){
for (int j=coins[i]; j<amount+1; j++){
if (dp[j-coins[i]]!=INT_MAX) /**/只有凑出当前金额j才能更新dp数组**
dp[j] = min(dp[j], dp[j-coins[i]]+1);
}
for (int j=0; j<amount+1; j++){
cout <<dp[j] <<" ";
}
cout <<endl;
}
if (dp[amount]==INT_MAX) return -1;
return dp[amount];
}
};
279. 完全平方数
//完全背包,组合题,先遍历物品
//dp[j]表示满足和为j的完全平方数使用的最少元素个数
// for (int j=i*i; j<n+1; j++) dp[j]=min(dp[j-i*i]+1, dp[i])
// dp[0]=0;
class Solution {
public:
int numSquares(int n) {
vector<int> dp(n+1, INT_MAX);
dp[0]=0;
for (int i=1; i*i<=n; i++){
for (int j=i*i; j<n+1; j++){
if (dp[j-i*i]!=INT_MAX && j>=i*i) dp[j] = min(dp[j-i*i]+1, dp[j]);
}
// for (int j=0; j<dp.size(); j++){
// cout << dp[j] <<" ";
// }
// cout << endl;
}
if (dp[n]==INT_MAX) return -1;
return dp[n];
}
};