天天看點

動态規劃 0-1背包問題

動态規劃在計算機算法中算是一類比較難的問題。 這個問題的難點在于如何抽象出狀态,根據狀态抽象出狀态轉移方程。

動态規劃中經典的問題是0-1背包問題,題目的很簡單,有N個物品,每個物品的重量是Wi, 物品的價值是Vi, 有一個容量為maxW的背包,問這個背包中能裝下物品的最大價值是多少。

那就是對于每一個物品, 有兩個可能性,要麼裝進去,要麼不裝。 可以分析一下這兩種情況。

裝進去: 1. 背包的剩餘空間能裝下該物品。 2. 裝下該物品可以使背包的總價值增大(成本效益高)。

不裝: 1. 裝不進去,剩餘空間不夠。 2. 剩餘空間夠,但是不能使背包的總價值增大(成本效益不高)。

是以我們可以得到這樣一個狀态轉移的方程:

dp[i][j] = max(dp[i-1][j], dp[i - 1][j - Wi] + Vi) 注意: j - Wi >= 0

dp 的行是物品的數量, 列是背包的容量。 這個方程就是上面解釋的,滿足條件,并且可以使背包的價值增大才能裝下該物品。

看一下python實作的背包算法。

def package_problem(weight, value, max_weight):
    n = len(weight) + 1
    m = max_weight + 1
    dq = [[0 for j in range(m)] for i in range(n)]
    path = [-1] * (n - 1)
    for i in range(1, n):
        for j in range(m):
            if j - weight[i - 1] >= 0:
                dq[i][j] = max(dq[i-1][j], dq[i-1][j - weight[i - 1]] + value[i - 1])

    max_value = dq[len(weight)][max_weight]

    last = m-1
    for i in range(n-1, 0, -1):
        for j in range(last, 0, -1):
            if j - weight[i - 1] >= 0:
                if dq[i][j] == dq[i - 1][j - weight[i-1]] + value[i - 1]:
                    path[i - 1] = i - 1
                    last = j - weight[i-1]
                    break

    print(path)
    return max_value

if __name__ == '__main__':
    weight = [0,4, 1, 1,3]
    value = [0,3000,2000,1500,2000]
    max_weight = 5
    ret = package_problem(weight, value, max_weight)
    print(ret)           

複制

輸出結果:

[-1, -1, 2, 3, 4]

5500

更多内容請關注: IT技術漫漫談