更多动态规划,参考牛客网总结:动态规划
目录
1.题目介绍
此题是一个完全背包问题,是一个经典的动态规划问题,想要理解完全背包的状态转移过程,首先需要理解01背包。所以,下面先介绍01背包和完全背包。
2.01背包
3.完全背包
具体代码如下:
int DP() {
for(int i = 1; i <= M; i++)
f[0][j] = -inf; // 负无穷,inf 可以为 1e8
f[0][0] = 0;
for(int i = 1; i <= N; i++)
for(int j = 0; j <= M; j++)
if(j >= v[i])
f[i][j] = max(f[i-1][j], f[i][j-v[i]] + w[i]);
else
f[i][j] = f[i-1][j];
int ans = 0;
for(int i = 0; i <= M; i++)
ans = max(ans, f[N][i]);
return ans;
}
我们还可以将上述代码优化为:
int DP() {
for(int i = 1; i <= M; i++)
f[j] = -inf; // 负无穷,inf 可以为 1e8
f[0] = 0;
for(int i = 1; i <= N; i++)
for(int j = v[i]; j <= M; j++)
f[j] = max(f[j], f[j-v[i]] + w[i]);
int ans = 0;
for(int i = 0; i <= M; i++)
ans = max(ans, f[i]);
return ans;
}
4.本题解法
如果我们将面值看作是物品,面值金额看成是物品的重量,每件物品的价值均为1,这样此题就是是一个恰好装满的完全背包问题了。不过这里不是求最多装入多少物品而是求最少,我们只需要将2.2节的转态转移方程中的max改成min即可,又由于是恰好装满,所以除了dp[0],其他都应初始化为INT_MAX
。完整代码如下:
int coinChange(vector<int>& coins, int amount) {
vector<int>dp(amount + 1, INT_MAX);
dp[0] = 0;
for(int i = 1; i <= coins.size(); i++)
for(int j = coins[i-1]; j <= amount; j++){
// 下行代码会在 1+INT_MAX 时溢出
// dp[j] = min(dp[j], 1 + dp[j - coins[i-1]]);
if(dp[j] - 1 > dp[j - coins[i-1]])
dp[j] = 1 + dp[j - coins[i-1]];
}
return dp[amount] == INT_MAX ? -1 : dp[amount];
}
注意上面1 + dp[j - coins[i-1]]
会存在溢出的风险,所以我们换了个写法。