欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

0-1背包问题-(递归,记忆化搜索,动态规划)

程序员文章站 2022-05-12 15:53:07
...

现有n件物品和一个容量为c的背包。第i件物品的重量是重量为w[i],价值是v[i]。已知对于一件物品必须选择取(用1表示)或者不取(用0表示),且每件物品只能被取一次(这就是“0-1”的含义)。求放置哪些物品进背包,可使这些物品的重量总和不超过背包容量,且价值总和最大。

关键在于分析出状态转移方程:
(1)i=0 当j<w[0]时,m[0][j]=0;当j>=w[0]时,m[0][j]=v[0]。

(2)i>0 当j<w[i],m[i][j]=m[i-1][j];当j>=w[i],m[i][j]=max{m[i-1][j-w[i]]+v[i],m[i-1][j]}。

具体分析过程参考链接:https://www.nowcoder.com/discuss/3574

递归:

# 直接递归
def _bestvalue(w, v, index, c):
    '''用[0, ...index]的物品填充容积为c的背包的最大价值'''
    if c <= 0 or index < 0:
        return 0
    # 两种方式:
    #   1.不放最后一件物品的最大价值
    #   2.放入最后一件物品的最大价值
    res = _bestvalue(w, v, index-1, c)
    if c >= w[index]:
        # 两种方式比较,取最大值
        res = max(res, _bestvalue(w, v, index-1, c-w[index]) + v[index])
    return res

def main(w, v, c):
    n = len(w)
    return _bestvalue(w, v, n-1, c)


w = [2,2,6,5,4]
v = [6,3,5,4,6]
c = 8
print(main(w, v, c))

记忆化搜索:

# 记忆化搜索
def _bestvalue(w, v, index, c):
    '''用[0, ...index]的物品填充容积为c的背包的最大价值'''
    if c <= 0 or index < 0:
        return 0
    if memory[index][c] != -1:
    	return memory[index][c]
    # 两种方式:
    #   1.不放最后一件物品的最大价值
    #   2.放入最后一件物品的最大价值
    res = _bestvalue(w, v, index-1, c)
    if c >= w[index]:
        # 两种方式比较,取最大值
        res = max(res, _bestvalue(w, v, index-1, c-w[index]) + v[index])
    memory[index][c] = res
    return memory[index][c]

def main(w, v, c):
    n = len(w)
    return _bestvalue(w, v, n-1, c)


w = [2,2,6,5,4]
v = [6,3,5,4,6]
c = 8
memory = [[-1]*(c+1) for i in range(len(w)+1)]
print(main(w, v, c))

动态规划:

# 动态规划
def bestvalue(w, v, c):
    if c <= 0:
        return 0
    dp = [[0]*(c+1) for i in range(len(w))]
    # 先把第一行只放第1个物品的情况处理了
    for i in range(0, c+1):
        if i >= w[0]:
            dp[0][i] = v[0]
    for i in range(1, len(w)):
        for j in range(0, c+1):
            if j < w[i]:  
                # 剩余容量不足,i号物品不放入背包
                dp[i][j] = dp[i-1][j]
            else:
                # 可以放入i号物品,计算状态转移方程
                dp[i][j] = max(dp[i-1][j], v[i] + dp[i-1][j-w[i]])

    # 计算选出的是哪些背包,1表示取,0表示不取
    x = [0] * len(w)
    for i in range(len(w)-1, 0, -1):
        if dp[i][c] > dp[i-1][c]:
            x[i] = 1
            c -= w[i]
    if c != 0:
        if dp[0][c] != 0:
            x[0] = 1
    return dp[-1][-1], x


w = [2,2,6,5,4]
v = [6,3,5,4,6]
c = 8
print(bestvalue(w, v, c))