動態規劃的基本思想是將待求解問題分解成若干個子問題,先求解子問題,並將這些子問題的解儲存起來,如果以後在求解較大子問題的時候需要用到這些子問題的解,就可以直接取出這些已經計算過的解而免去重複運算。儲存子問題的解可以使用填表方式,例如儲存在陣列中。
用乙個實際例子來體現動態規劃的演算法思想——硬幣找零問題。
硬幣找零問題描述:現存在一堆面值為 v1、v2、v3 … 個單位的硬幣,問最少需要多少個硬幣才能找出總值為 t 個單位的零錢?假設這一堆面值分別為 1、2、5、21、25 元,需要找出總值 t 為 63 元的零錢。
很明顯,只要拿出 3 個 21 元的硬幣就湊夠了 63 元了。
基於上述動態規劃的思想,我們可以從 1 元開始計算出最少需要幾個硬幣,然後再求 2 元、3元…每一次求得的結果都儲存在乙個陣列中,以後需要用到時則直接取出即可。那麼我們什麼時候需要這些子問題的解呢?如何體現出由子問題的解得到較大問題的解呢?
其實,在我們從 1 元開始依次找零時,可以嘗試一下當前要找零的面值(這裡指 1 元)是否能夠被分解成另乙個已求解的面值的找零需要的硬幣個數再加上這一堆硬幣中的某個面值之和,如果這樣分解之後最終的硬幣數是最少的,那麼問題就得到答案了。
單是上面的文字描述太抽象,先假定以下變數:
values : 儲存每一種硬幣的幣值的陣列
valuekinds :幣值不同的硬幣種類數量,即values陣列的大小
money : 需要找零的面值
coinsused : 儲存面值為 i 的紙幣找零所需的最小硬幣數
演算法描述:
當求解總面值為 i 的找零最少硬幣數 coinsused[ i ] 時,將其分解成求解 coinsused[ i – cents]和乙個面值為 cents 元的硬幣,由於 i – cents < i , 其解 coinsused[ i – cents] 已經存在,如果面值為 cents 的硬幣滿足題意,那麼最終解 coinsused[ i ] 則等於 coinsused[ i – cents] 再加上 1(即面值為 cents)的這乙個硬幣。
下面用**實現並測試一下:
public class coinschange} }
// 儲存最小硬幣數
coinsused[cents] = mincoins;
system.out.println("面值為 " + (cents) + " 的最小硬幣數 : "
+ coinsused[cents]);
} }
public static void main(string args) ;
// 需要找零的面值
int money = 63;
// 儲存每乙個面值找零所需的最小硬幣數,0號單元捨棄不用,所以要多加1
int coinsused = new int[money + 1];
makechange(coinvalue, coinvalue.length, money, coinsused);
} }
測試結果:
面值為 1 的最小硬幣數 : 1 面值為 2 的最小硬幣數 : 2 面值為 3 的最小硬幣數 : 3 面值為 4 的最小硬幣數 : 4 面值為 5 的最小硬幣數 : 1 面值為 6 的最小硬幣數 : 2 ... ... 面值為 60 的最小硬幣數 : 3 面值為 61 的最小硬幣數 : 4 面值為 62 的最小硬幣數 : 4 面值為 63 的最小硬幣數 : 3
動態規劃演算法求解硬幣找零問題
1.問題描述 現存在一堆面值為 v1 v2 v3 個單位的硬幣,問最少需要多少個硬幣才能找出總值為 t 個單位的零錢?假設這一堆面值分別為 1 2 5 21 25 元,需要找出總值 t 為 63 元的零錢。2.分析 動態規劃的基本思想是將待求解問題分解成若干個子問題,先求解子問題,並將這些子問題的解...
動態規劃演算法求解硬幣找零問題(Java)
詳見 動態規劃的基本思想是將待求解問題分解成若干個子問題,先求解子問題,並將這些子問題的解儲存起來,如果以後在求解較大子問題的時候需要用到這些子問題的解,就可以直接取出這些已經計算過的解而免去重複運算。儲存子問題的解可以使用填表方式,例如儲存在陣列中。用乙個實際例子來體現動態規劃的演算法思想 硬幣找...
動態規劃演算法 硬幣問題
1.問題描述 n種硬幣,面值分別是 v 1 v 2 v n 給定非負整數s,可以選用多少個硬幣,使得面值之和恰好為s?求出硬幣數目的最大值和最小值。2.分析 初始狀態為 s,目標狀態為0。若當前狀態在i,每使用乙個硬幣j,狀態便轉移到i v j 我們用d i 表示求總和為i的最少硬幣數量 其實就是動...