1. 程式人生 > >從自動販賣機找零看Python中的動態規劃問題

從自動販賣機找零看Python中的動態規劃問題

問題描述

假設在某國存在[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]