背包问题(0-1背包问题和完全背包问题)

一.  0-1背包问题

给了一些物品的重量和价值,背包只能装下一定重量的物品,求背包能装物品的最大价值(0-1背包问题约定每个物品最多只能用一次)。

w = [5, 4, 7 ,2 ,6] #重量
p = [12,3,10, 3, 6] #价值
v = 12 #包能装下的总重量
n = 5 #物品个数

1)不超过总重量(不要求装满)的情况下,价值最大

w = [5, 4, 7 ,2 ,6] #重量
p = [12,3,10, 3, 6] #价值
v = 12 #包能装下的总重量
n = 5 #物品个数

def dynamic1(w, p, v, n):
    dp = [[0 for i in range(v+1)] for j in range(n+1)] #初始化,dp[i][j]表示: 前i个物品,总重量不超过j的情况下的最大价值
    for i in range(1, n+1):
        for j in range(1, v+1):
            if w[i-1] <= j: #w[i-1]是第i个物品的重量
                dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i-1]] + p[i-1]) #装第i个物品or不装第i个物品
            else:
                dp[i][j] = dp[i-1][j]
    return dp[-1][-1]

# 对空间复杂度进行优化,由二维数组变成一维
def dynamic2(w, p, v, n):
    dp = [0 for j in range(v+1)]
    for i in range(1, n+1):
        for j in range(v, 0, -1):  # 从后往前防止dp[j-w[i-1]]被覆盖
            if j >= w[i-1]:
                dp[j] = max(dp[j], dp[j-w[i-1]] + p[i-1])
            #else: dp[j] = dp[j]
    return dp[-1]

2)要求背包装满的情况下,价值最大

与第一种情况不同的是,这时候的初始化状态需要调整 ,除了dp[i, 0]仍然等于0,其他的dp[i,j]= -inf  
这是因为初始状态,背包没有任何物品,只有当背包容量为0时,才可以看作背包被装满了,符合条件,此时价值为0.

def dynamic3(w, p, v, n):
    dp = [[0 if i == 0 else float('-inf') for i in range(v+1)] for j in range(n+1)] 
    for i in range(1, n+1):
        for j in range(1, v+1):
            if w[i-1] <= j: 
                dp[i][j] = max(dp[i-1][j], dp[i-1][j-w[i-1]] + p[i-1]) 
            else:
                dp[i][j] = dp[i-1][j]
    return dp[-1][-1]

# 空间优化
def dynamic4(w, p, v, n):
    dp = [0 if i == 0 else float('-inf') for i in range(v+1)]
    for i in range(1, n+1):
        for j in range(v, 0, -1):
            if w[i-1] <= j: 
                dp[j] = max(dp[j], dp[j-w[i-1]] + p[i-1]) 
    return dp[-1]

二. 完全背包问题(不限制每个物品的使用次数)

完全背包问题的一种简单实现与与0-1背包问题只有内部的循环次序不同而已。

引用一段话进行解释(链接:https://www.jianshu.com/p/7a4e6071bc02)“ 为什么这样 一改就可行呢?首先想想为什么 0-1背包问题中要按照 w=W..0 的逆序来循环。这是因为 要保证第 i 次循环中的状态 f[i][w]是由状态 f[i-1][w-w[i]]递推而来。换句话 说,这正是为了保证每件物品只选一次,保证在考虑“选入第 i 件物品”这件策 略时,依据的是一个绝无已经选入第 i 件物品的子结果 f[i-1][w-w[i]]。而现 在完全背包的特点恰是每种物品可选无限件,所以在考虑“加选一件第 i 种物 品”这种策略时,却正需要一个可能已选入第 i 种物品的子结果 f[i][w-w[i]],所以就可以并且必须采用 w=0..W 的顺序循环。这就是这个简单的程序为何成立的道理。”

def dynamic2(w, p, v, n):
    dp = [0 for j in range(v+1)]
    for i in range(1, n+1):
        for j in range(1, v+1):  # 从前往后
            if j >= w[i-1]:
                dp[j] = max(dp[j], dp[j-w[i-1]] + p[i-1])
            #else: dp[j] = dp[j]
    return dp[-1]

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值