动态规划-01背包问题、完全背包

背包问题

题目:有四个物品,书包总容量为8,背包最多能装入价值为多少的物品

物品编号1234
物品体积2345
物品价值3456

0-1背包:物品件数为1
完全背包:物品件数为有限件

解法归纳

  1. 如果装不下当前物品,那么n个物品的最住组合和前n-1个物品的最住组合是一样的。

  2. 如果装得下当前物品。

    假设1:装当前物品,在给当前物品预留了相应空间的情况下,前n-1个物品的最佳组合加上当前物品的价值就是总价值。
    假设2:不装当前物品,那么前n个物品的最佳组合和前n-1个物品的最佳组合是一样的。
    选取假设1和假设2中较大的价值,为当前最佳组合的价值。

  3. 回溯:从表的右下角开始回溯,如果发现前n个物品最佳组合的价值和前n-1个物品最佳组合的价值一样,说明第n个物品没有被装入。
    否则,第n个物品被装入。

01 背包

# 01 背包
import numpy as np
weight = [2,3,4,5]  # 物品重量
price = [3,4,5,6]  # 物品价值
weight_most = 10

def fullbag(weight, price, weight_most):  # return max value
    num = len(weight)  # 获取物品总量
    weight.insert(0, 0)  # 不存在第0个物品,故插入一个0
    price.insert(0, 0)  # 同上
    bag = np.zeros((num + 1, weight_most + 1), dtype=np.int32)  # 使用numpy快速建立数组,下标从零开始
    #     bag0 = [0 for j in range(weight_most+1)]          #不导入np三方库
    #     bag = [bag0 for i in range(num+1)]

    for i in range(1, num + 1):  # 这俩循环的取值为行与列,每件物品进行循环
        for j in range(1, weight_most + 1):  # 从轻的开始拿
            if weight[i] <= j:
                bag[i][j] = max(bag[i - 1][j - weight[i]] + price[i], bag[i - 1][j])
            else:
                bag[i][j] = bag[i - 1][j]
    print(bag)

    # 回溯计算应该装入的体积
    op_volume = []
    j = weight_most
    for i in reversed(range(1,num+1)):
        if bag[i][j] != bag[i-1][j]:
            op_volume.append(weight[i])
            j=j-weight[i]
    print("装入的体积",op_volume)
    return bag[-1, -1]


if __name__ == '__main__':
    result = fullbag(weight, price, weight_most)
    print("装入的价值",result)

完全背包

# 完全背包

import numpy as np

weight = [2,3,4,5]  # 物品重量
price = [3,4,5,6]  # 物品价值
weight_most = 8

def fullbag(weight, price, weight_most):  # return max value
    num = len(weight)  # 获取物品总量
    weight.insert(0, 0)  # 不存在第0个物品,故插入一个0
    price.insert(0, 0)  # 同上
    bag = np.zeros((num + 1, weight_most + 1), dtype=np.int32)  # 使用numpy快速建立数组,下标从零开始
    knum = np.zeros((num + 1, weight_most + 1), dtype=np.int32)
    #     bag0 = [0 for j in range(weight_most+1)]          #不导入np三方库
    #     bag = [bag0 for i in range(num+1)]

    for i in range(1, num + 1):  # 这俩循环的取值为行与列,每件物品进行循环
        for j in range(1, weight_most + 1):  # 从轻的开始拿
            if weight[i] <= j:
                k=0
                while (k * weight[i] <= j):
                    bag[i][j] = max(bag[i][j - k * weight[i]] + k * price[i], bag[i - 1][j])
                    if bag[i][j - k * weight[i]] + k * price[i] > bag[i - 1][j]:
                        knum[i][j] = k
                    k=k+1
            else:
                bag[i][j] = bag[i - 1][j]
    print(bag)

    # 回溯计算应该装入的体积
    j = weight_most
    for i in reversed(range(1, num + 1)):
        if bag[i][j] != bag[i - 1][j]:
            if (knum[i][j]>0):
                print("装入物品{}共{}件".format(i,knum[i][j]))
            j=j-knum[i][j]*weight[i]

    return bag[-1, -1]
if __name__ == '__main__':
    result = fullbag(weight, price, weight_most)
    print("装入的价值", result)

完全背包优化

优化如上k值
在这里插入图片描述

# 完全背包优化

import numpy as np
weight = [2,3,4,5]  # 物品重量
price = [3,4,5,6]  # 物品价值
weight_most = 8
def fullbag(weight, price, weight_most):  # return max value
    num = len(weight)  # 获取物品总量
    weight.insert(0, 0)  # 不存在第0个物品,故插入一个0
    price.insert(0, 0)  # 同上
    bag = np.zeros((num + 1, weight_most + 1), dtype=np.int32)  # 使用numpy快速建立数组,下标从零开始
    #     bag0 = [0 for j in range(weight_most+1)]          #不导入np三方库
    #     bag = [bag0 for i in range(num+1)]

    for i in range(1, num + 1):  # 这俩循环的取值为行与列,每件物品进行循环
        for j in range(1, weight_most + 1):  # 从轻的开始拿
            if weight[i] <= j:
                bag[i][j] = max(bag[i][j - weight[i]] + price[i], bag[i - 1][j])
            else:
                bag[i][j] = bag[i - 1][j]
    print(bag)
    return bag[-1, -1]

    # 回溯计算应该装入的体积
    j = weight_most
    k=1
    for i in reversed(range(1,num+1)):
        if bag[i][j] != bag[i-1][j]:
            print("装入物品{}共{}件".format(i, knum[i][j]))
        j = j - knum[i][j] * weight[i]
    print("装入的体积",op_volume)
    return bag[-1, -1]

if __name__ == '__main__':
    result = fullbag(weight, price, weight_most)
    print("装入的价值",result)

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值