1 换硬币问题
给定任意问题,我们总能找到该问题最简单的案例,针对简单的例子,我们往往能很快得到答案。再考虑难一些的例子,即更常规的例子,我们如何解决呢?显然,我们希望大事化小,小化了,因此,我们首先考虑原问题是否可分为子问题?显然该问题是由子问题amount-1的最优解组成。具备最优子结构性质的问题往往用动态规划解决。此外,另一个十分重要的问题就是如何确定递推表达式,也称为状态转移方程。如何确定状态转移方程呢?
(1)确定状态
该问题中,子问题和原问题的变量是什么呢?
金额
硬币面额
硬币数目:无限多硬币,不影响
(2)确定状态转移函数定义
opt(n)表示凑出金额为n,所需最少的硬币数
(3)如何确定最优
从coins中任意选择一枚硬币,金额数减少,怎么选才能使硬币数目最少?我们将各个选择下所需硬币数求出来,最优决策就是能使硬币数目最少的决策方式。因此我们获取状态转移方程:
// 回溯
int coinChange(vector<int>& coins, int amount){
if (amount == 0)
{
return 0;
}
else if (amount < 0)
{
return -1;
}
else
{
int res = INT16_MAX;
for (int i = 0;i < coins.size();i++)
{
int subp = coinChange(coins,amount - coins[i]);
if (subp != -1)
{
res = min(res,subp +1 );
}
}
if (res == INT16_MAX)
{
return -1;
}else
{
return res;
}
}
}
//DP
int coinChange(vector<int> &coins, int amount)
{
if (amount == 0)
return 0;
if (amount < 0)
return -1;
vector<int> opt(amount+1, amount+1);
opt[0] = 0;
int n = coins.size();
for (int i = 1; i <= amount; i++)
{
for (int j = 0; j < n; j++)
{
if ((i - coins[j]) >= 0)
{
opt[i] = min(opt[i], opt[i - coins[j]] + 1);
}
}
}
if (opt[amount] >= amount + 1)
{
return -1;
}
return opt[amount];
}
reference:
https://labuladong.gitbook.io/algo/dong-tai-gui-hua-xi-lie/dong-tai-gui-hua-xiang-jie-jin-jie