Knapsack Problem,背包问题

Last Updated: 2024-03-10 12:17:38 Sunday

-- TOC --

01背包

有N个物品,分别有重量W和价格P两个属性,现在有一个包,可以容下最多T重量的物品,问将哪些物品放入包内,在不超重的情况下,物品价值总量最大。物品不可分割。

01或写成0/1,0-1...表示每个物品只能拿一次。如果两个物品相同,拿一次就少一个。

递归

def knapsack(wlst, vlst, weight, value):
    assert len(wlst) == len(vlst)
    if weight < 0:
        return -1
    if not wlst or weight==0:
        return value
    a = knapsack(wlst[1:], vlst[1:], weight-wlst[0], value+vlst[0])
    b = knapsack(wlst[1:], vlst[1:], weight, value)
    return max(a,b)


T = 4
W = [4,5,1]
P = [1,2,3]
print(knapsack(W,P,T,0))  # 3

T = 3
W = [4,5,6]
P = [1,2,3]
print(knapsack(W,P,T,0))  # 0

T = 10
W = [1,2,3,4,5]
P = [5,4,3,2,1]
print(knapsack(W,P,T,0))  # 14

$$T(n)=2T(n-1)+1=O(2^n)$$

换个写法:

class knapsack():

    def prep(self, wlst, vlst):
        self.length = len(wlst)
        assert self.length == len(vlst)
        self.wlst = wlst
        self.vlst = vlst

    def go(self, idx, weight, value):
        if weight < 0:
            return -1
        if idx==self.length or weight==0:
            return value
        a = self.go(idx+1, weight-self.wlst[idx], value+self.vlst[idx])
        b = self.go(idx+1, weight, value)
        return max(a,b)


T = 4
W = [4,5,1]
P = [1,2,3]
kp = knapsack()
kp.prep(W,P)
print(kp.go(0,T,0))

T = 3
W = [4,5,6]
P = [1,2,3]
kp = knapsack()
kp.prep(W,P)
print(kp.go(0,T,0))

T = 10
W = [1,2,3,4,5]
P = [5,4,3,2,1]
kp = knapsack()
kp.prep(W,P)
print(kp.go(0,T,0))

Dynamic Programming

Top-Down

class knapsack():

    def prep(self, wlst, vlst):
        self.length = len(wlst)
        assert self.length == len(vlst)
        self.wlst = wlst
        self.vlst = vlst
        self.rec = {}

    def go(self, idx, weight, value):
        if (idx,weight) in self.rec:
            return self.rec[idx,weight]
        if weight < 0:
            return -1
        if idx==self.length or weight==0:
            return value
        a = self.go(idx+1, weight-self.wlst[idx], value+self.vlst[idx])
        b = self.go(idx+1, weight, value)
        t = max(a,b)
        self.rec[idx,weight] = t
        return t

有多少子问题?\(O(n\cdot weight)\)

Bottom-Up

本文链接:https://cs.pynote.net/ag/dp/202403101/

-- EOF --

-- MORE --