动态规划也可以用来解决零钱兑换问题。这个问题是给定不同面额的硬币和一个总金额,计算出组成该总金额所需的最少硬币数。如果不能凑出总金额,则返回 -1。
好的,让我们通过一个具体的例子来说明动态规划零钱兑换的过程。
假设有以下情况:
1.给定面额为 [1, 2, 5] 的硬币。
2.目标总金额为 11。
我们的目标是计算出组成总金额 11 所需的最少硬币数。
3.初始化:
我们首先初始化一个长度为 12 的数组 dp,其中 dp[i] 表示组成金额 i 所需的最少硬币数。由于金额从 0 到 11,所以数组长度为 12。
dp = [0, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF, INF]
这里用 INF 表示正无穷,表示当前状态下还不能组成对应的金额。
4.状态转移:
现在我们开始考虑状态转移方程。我们从金额为 1 开始,逐步计算到目标金额 11。
5.对于金额为 1,我们有以下选择:
6.使用面额为 1 的硬币,需要 1 枚硬币。
dp[1] = min(dp[1], dp[1 - 1] + 1) = min(INF, dp[0] + 1) = min(INF, 0 + 1) = 1
7.对于金额为 2,我们有以下选择:
8.使用面额为 1 的硬币,需要 1 枚硬币。
9.使用面额为 2 的硬币,需要 1 枚硬币。
dp[2] = min(dp[2], dp[2 - 1] + 1, dp[2 - 2] + 1) = min(INF, dp[1] + 1, dp[0] + 1) = min(INF, 1 + 1, 0 + 1) = 1
10.对于金额为 3,我们有以下选择:
11.使用面额为 1 的硬币,需要 1 枚硬币。
12.使用面额为 2 的硬币,需要 2 枚硬币。
dp[3] = min(dp[3], dp[3 - 1] + 1, dp[3 - 2] + 1) = min(INF, dp[2] + 1, dp[1] + 1) = min(INF, 1 + 1, 1 + 1) = 2
13.对于金额为 4,我们有以下选择:
14.使用面额为 1 的硬币,需要 1 枚硬币。
15.使用面额为 2 的硬币,需要 2 枚硬币。
dp[4] = min(dp[4], dp[4 - 1] + 1, dp[4 - 2] + 1) = min(INF, dp[3] + 1, dp[2] + 1) = min(INF, 2 + 1, 1 + 1) = 2
16.依次类推,我们可以计算出 dp[5]、dp[6]、dp[7]、dp[8]、dp[9]、dp[10]、dp[11]。
17.结果输出:
根据计算得到的 dp 数组,我们可以看到 dp[11] = 3,表示组成总金额 11 所需的最少硬币数为 3。
所以,对于给定面额为 [1, 2, 5] 的硬币和总金额 11,我们需要 3 枚硬币才能凑出总金额 11。
c++代码
#include <iostream>
#include <vector>
#include <climits>
using namespace std;
int coinChange(vector<int>& coins, int amount) {
vector<int> dp(amount + 1, INT_MAX);
dp[0] = 0; // 表示凑出金额为0的最小硬币数为0
for (int i = 1; i <= amount; ++i) {
for (int coin : coins) {
if (i - coin >= 0 && dp[i - coin] != INT_MAX) {
dp[i] = min(dp[i], dp[i - coin] + 1);
}
}
}
return dp[amount] == INT_MAX ? -1 : dp[amount];
}
int main() {
vector<int> coins = {1, 2, 5};
int amount = 11;
cout << "最少硬币数: " << coinChange(coins, amount) << endl; // 输出:3
return 0;
}