一,問題描述
給定一組硬幣數,找出一組最少的硬幣數,來找換零錢n。
這類問題由於給定的硬幣面值與數量的不同,可能演化出很多種不同的版本,這裡先講最簡單的兩種形式。
二,貪婪法求解硬幣找零問題
貪婪法的思路很簡單,不斷地從總找零值裡減去面值最大的硬幣。如果找零的值小於最大的硬幣值,則嘗試第二大的硬幣,依次類推。
c++**實現如下:
1 #include 2貪婪法實現硬幣找零3using
namespace
std;45
intmain()
620 cout
21 }
但是使用貪婪法求解硬幣找零問題,必須要讓給定的硬幣面值滿足一定的先決條件,否則求出的解不是最優解!
正例:給定一組硬幣:1,5,10,20。n=30。求最小硬幣數。
答案顯然是2,因為先考慮25,剩5,取乙個5元。最後結果為2。
給定一組硬幣:1,5,20,25。n=40。求最小硬幣數。
如果用貪婪法,先考慮25,剩餘15,取3個5元。最後結果為4。
但是很顯然,如果直接使用20的硬幣,則2個即可。由此可見,貪婪法的解在這個問題裡面並不是最優的。對於這種情況,就需要使用動態規劃進行求解。
而使用貪婪法能夠求出最優解的條件是:每個大的面值,都是小的面值的整數倍。
從上面的正例來看, 20是10,5,1的整數倍,同理10是5,1的整數倍,以此類推。而在反例中,25不是20的整數倍。
證明方法可以見這篇部落格,博主的證明非常詳細。
貪婪演算法硬幣找零最優解問題證明:而在這裡我們只體會一下原因:只有在大的面額是小的面額的整數倍的情況下,先找大的金額才一定時最優的。例如20是10的倍數,則所有能用20抵扣的金額,都一定比用10來抵扣花的數量少。
反之則不一定。例如25和20,在湊40時,兩個20即可,而25還需要和更小的金額搭配。
二,動態規劃求解硬幣找零問題
根據動態規劃的思想,我們將給n找零的問題分解成「給更小金額找零」的子問題。最後,利用小面值目標的解,去得出大面值目標的解。具體實現,首先是先從小面值的找零開始,將解決方案依次存入動態規劃陣列,一直往大面值累加,最後直接輸出動態規劃陣列指定位置的值也即大面值找零所需的最少硬幣數,演算法實現如下:
int coinchange(vector& coins, int動態規劃實現硬幣找零amount) ;
for (int i = 0; i < n; ++i)
for (int i = 1; i <=amount; ++i)}}
if (coin_num[amount] == 0
)
return -1
;
else
return
coin_num[amount];
}
硬幣找零問題(動態規劃)
給定指定的硬幣種類,面值為 1,3,5 在此具體化些 給定所找零的錢數 sum,給出最少的硬幣找零數,每個種類的硬幣無限使用。看到這問題,當時我想到用貪心演算法來求解,最後求解方案因為巧合對了,後來在網上看到動態規劃的題目,才知道貪心演算法得不到最優解,比如 給定 面值為 1,3,4,給定找零數為 ...
硬幣找零問題 動態規劃問題
看到了 這文章,由於我不太懂他的 所以我按他的題和思路,寫了 思路我就不寫了,就是動態規劃的思路,先保證區域性最優,再慢慢向全區域性最優 include include include include using namespace std const int m 100 int coinsum m...
動態規劃 硬幣找零
時間限制 1000 ms 記憶體限制 65535 kb 描述在現實生活中,我們經常遇到硬幣找零的問題,例如,在發工資時,財務人員就需要計算最少的找零硬幣數,以便他們能從銀行拿回最少的硬幣數,並保證能用這些硬幣發工資。我們應該注意到,人民幣的硬幣系統是 100,50,20,10,5,2,1,0.5,0...