從自動販賣機找零看Python中的動態規劃問題
阿新 • • 發佈:2019-02-16
問題描述
假設在某國存在[1,x1,x2,x3,...,xn]多種貨幣,該國的自動販賣機在找零時要遵循一個原則——“找零的總張數最少”。那麼,該如何編寫程式,幫助自動販賣機自動找零呢?
問題分析
解決這一問題的最直接思路是窮舉法。假設需要找零Y元,那麼就通過所有的小於Y的貨幣,列舉出找零的所有方案,進而比較哪個總張數最少。這種思路需要在計算中蘊含有大量的重複,時間複雜度極大。
類似問題的一個有效解法是使用動態規劃的思想來處理。
求解找零所需要最少貨幣數
以面值為1,5,10,25的貨幣為例:
解決這一問題的關鍵在於,利用類似的等式,不斷縮小問題的規模。當問題縮小為“需要多少張貨幣來找0元”時,問題的答案顯然是0。
我們需要額外做的就是建立一個列表,用以儲存比要計算的找零需求更小的需求。
# need_change 為需要找零的金額, # currency_list 為該國貨幣的面值列表, # num_list 為需要找零的最少貨幣數目, num_list的長度至少為(need_change+1) def giveChange(need_change, currency_list, num_list): for change in range(need_change+1): #從0開始計算最少需要的貨幣數 for currency in currency_list: #遍歷每一種貨幣 if (change-currency >= 0) and (num_list[change-currency]+1<num_list[change]): #計算最少貨幣需求數 num_list[change] = num_list[change-currency] + 1 return def main(): need_change = 63 currency_list = [1,5,10,21,25] num_list = list(range(need_change+1)) #初始化num_list為0到need_change,共(need_change+1)個數 giveChange(need_change, currency_list, num_list) print("%d 需要 %d 個貨幣來找零"%(need_change, num_list[need_change])) if __name__ == "__main__": main()
執行結果為:
63 需要 3 個貨幣來找零
僅僅輸出了正確的貨幣數目是不夠的,我們還需要輸出具體是哪些面值的貨幣。
自動找零問題的解決
如同常見的,最短路徑的記錄一樣。為輸出具體是需要找哪些面值的貨幣的零錢,我們需要再上一步驟的基礎上記錄下每步求解最小化使用的貨幣。
為此,我們需要在新增一個列表,用以記錄這個數值。
# need_change 為需要找零的金額, # currency_list 為該國貨幣的面值列表, # num_list 為需要找零的最少貨幣數目, num_list的長度至少為(need_change+1) # used_list 為需要找零的最少貨幣數目, 長度與num_list相同 def giveChange(need_change, currency_list, num_list, used_list): for change in range(need_change+1): #從0開始計算最少需要的貨幣數 for currency in currency_list: #遍歷每一種貨幣 if (change-currency >= 0) and (num_list[change-currency]+1<=num_list[change]): #計算最少貨幣需求數 num_list[change] = num_list[change-currency] + 1 used_list[change] = currency #記錄消耗的貨幣 return # 返回需要的貨幣 def showChange(need_change, used_list): give_list = [] while need_change > 0: give_list.append(used_list[need_change]) need_change -= used_list[need_change] give_list.sort() #排序 return give_list def main(): need_change = 64 #需要找零的錢數 currency_list = [1,5,10,21,25] # 該國的貨幣面值列表 num_list = list(range(need_change+1)) #初始化num_list為0到need_change,共(need_change+1)個數 used_list = list(range(need_change+1)) #初始化used_list為0到need_change,共(need_change+1)個數 giveChange(need_change, currency_list, num_list, used_list) print("%d 需要 %d 個貨幣來找零"%(need_change, num_list[need_change])) give_list = showChange(need_change, used_list) print(give_list) if __name__ == "__main__": main()
計算結果為:
64 需要 4 個貨幣來找零
[1, 21, 21, 21]