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