1. 程式人生 > 資訊 >為媽媽下次廚:加加調味組合 4 瓶 14.8 元好價(商超 9.9 元/瓶)

為媽媽下次廚:加加調味組合 4 瓶 14.8 元好價(商超 9.9 元/瓶)


title: 0-1揹包問題
date: 2022-05-11 11:02:33
tags: 演算法

0-1揹包問題

蠻力列舉法

依次列出所有可能情況

n表示有n個商品, C表示容量

其中顏色相同的是需要重複計算的

帶備忘的遞迴

為了解決這個問題->需要大量計算重複的過程,這個時候我們可以引進一個“備忘錄”,如果遇到需要重複計算的式子的話,我們可以直接重備忘錄中獲取。

虛擬碼的實現:

KnapsackMR(i, c)

​ 輸入:商品集合{1,...,i},揹包容量c

​ 輸出:最大總價格P[i, c]

​ if(c < 0) then 容量為零 返回負無窮

​ return 負無窮

​ end

​ if i ≤ 0 then 如果商品的個數小於零的話,返回零

​ return 0

​ end

​ if P[i, c] ≠ NULL then 如果備忘錄中有這個的話就不用計算 直接返回即可

​ return P[i, c]

​ end

​ P1 = KnapsackMR(i-1, c-vi)

​ P2 = KnapasckMR(i-1, c)

​ p[i, c] <= max{P1 + pi, P2}

​ return P[i, c]

計算順序:

為了能夠不遞推,直接求解P[i,c],這就需要我們事先把備忘錄表,全部填寫上去

p[i,c]確定的方法需要讓p[i-1, c]和p[i-1,c-vi]+pi 相比較,選取其中較大的哪一個

程式碼實現

# 揹包問題
# 第一個引數為商品數量
# 第二個引數為揹包容量
# 第三個引數為價格表容量表
def memo_rec_matrix(num_commodity, size_knapsack, Price):
    # 建立備忘錄格式
    memo = [ [ [] for i in range(size_knapsack+1)] for m in range(num_commodity+1)]

    # 建立追蹤表格 0 表示不選擇該商品,1表示選擇該商品
    rec = [ [ [] for i in range(size_knapsack+1)] for m in range(num_commodity+1)]

    # 初始化備忘錄 和 追蹤表格
    for m in range(size_knapsack+1):
        memo[0][m] = 0
        rec[0][m] = 0
    

    for m in range(num_commodity+1):
        memo[m][0] = 0
        rec[m][0] = 0
    
    # 當我們商品數量為1 - num_commodity 的時候各種情況
    for i in range(1, num_commodity+1):
        # 當揹包容量為1-size_knapsck的時候的各種情況
        for m in range(1, size_knapsack+1):
            # 如果揹包容量小於第i個商品的體積的話,
            #   就讓memo陣列對應的 商品數量i行  和  揹包容量m列的位置 等於上一行的這一列的容量,
            #       因為上一行這一列的容量是 這個容量是沒有i個商品的容量最大值, 並且設定rec[i][m]這個位置為零
            if m < Price[0][i-1]:
                memo[i][m] = memo[i-1][m]
                rec[i][m] = 0
            # 如果揹包容量大於第i個商品的體積的話,需要進行判斷
            else:
                # 如果加上第i個商品之後的價值 小於沒有加上該商品的價值的話,
                #   那麼就把該位置設定成沒有加上第i個商品的時候價值
                #      把rec該位置的座標賦值為0 因為沒有選擇了該商品 
                if memo[i-1][m] > memo[i-1][m-Price[0][i-1]]+Price[1][i-1]:
                    memo[i][m] = memo[i-1][m]
                    rec[i][m] = 0
                # 如果大於的話直接賦值就行
                #   把rec該位置的座標賦值為1 因為選擇了該商品
                else:
                     memo[i][m] = memo[i-1][m-Price[0][i-1]]+Price[1][i-1]
                     rec[i][m] = 1
    return memo, rec
                

# 追蹤陣列
def track(rec, price):
    rec_num_line = len(rec)-1
    rec_num_column = len(rec[0])-1

    while(True):
        # 迴圈條件 商品數量為0
        if rec_num_line == 0:
            break
        elif rec[rec_num_line][rec_num_column] == 0:
            rec_num_line -= 1
        else:
            print(rec_num_line)
            rec_num_line -= 1
            rec_num_column -= price[0][rec_num_line]

price = [
    [10,3,4,5,4], # 體積
    [24,2,9,10,9]  # 價格
]


# 商品數量
num_commodity = 5
# 揹包容量
size_knapsack = 13


memo, rec = memo_rec_matrix(num_commodity,size_knapsack,price)