用动态规划解决0-1背包问题

用动态规划解决0-1背包问题

问题概述

给定以有限容量(capacity/space)的背包,和一些由体积(space)和价值的(value)的物品,求一个方案,用这个背包能够装下更多的物品

解决思路

  1. 先解决前i个物品在容量为任意j(最大值为背包容量)的背包下,能够装下的价值量
  2. 再解决在1的基础上继续解决前i+1个物品在任意j的背包下,能装下的最大价值量。所以,DP(i+1,j)=max{DP(i,j),DP(i,j-s(i+1))+v(i+1)}。
  3. 第一种情况即第i+1个物品未被装进来,此时问题等价于“前i个物品,在容量为j时最大装载量”,第二种情况即第i+1个物品被装进来了,此时问题等价于“前i个物品在容量为j-s(i+1)时的最大装载量”,显然可得,当j<s(i+1)时,第二种情况不可能成立,所以只取第一种情况。
  4. 在3的基础上,我们可以提出两个边界条件:DP(0,j)=0 即无物品可装时,无论背包容量有多大,装载量皆为0。DP(i,0)=0,即背包没有容量时,无论有什么物品,都不可能装下。

实现思路

为此,我们可以实现一个二维矩阵DP[i,j],来存储我们上面提到的DP(i,j).

其在初始化时,需要将第一行和第一列都初始化为0.然后逐行逐列根据上一节第2条所提到的情况进行更新。

到此为止,我们获得了在任意容量和任意物品供选择的情况下,所能装下的最大价值。我们还需要得到具体的装载方案。

为此,我们可以用以下方案来得到具体的装载方案。

  1. 访问DP(n,v),与DP(n-1,v)做对比,若相等则说明存在物品n被放入背包的最佳方案。
  2. 同时与DP(n-1,v-s(n))+v(n)做对比,若相等则说明存在物品n-1 未被放入背包的最佳方案。
  3. 对1和2中,符合条件(相等)的元素,做重复操作,直至第一个物品被确认是否存在被放入背包的最佳方案。
  4. 需要注意的是,如果被访问的元素,出现DP[i,j]其中j <s(i),那实现DP[i,j]的方案中必然不可能存在物品i。
  5. 得到这个方案的过程类似于一个树状图。

囿于时间仓促,本人用深度优先的方式,实现仅给出其中一种最佳方案的方式。

代码实现

为了使矩阵操作更加高效和便捷,这里使用了numpy.ndarray

dp_01.py:

import numpy as np
class dp_01:
    def __init__(self,items,capacity):
        self.items=items
        self.num=len(self.items)
        self.capacity=capacity
        self.matrix=np.zeros((self.num+1,self.capacity+1))
        self.matrix=np.asarray(self.matrix)

    def update_the_matrix(self):
        #需注意的是,物品的计数从第1个开始,而不是第0个
        #为了同记载物品情况的元组/列表相适配,items[i-1]指的就是第i个物品。
        for i in range(1,self.num+1,1):
            for j in range(1,self.capacity+1,1):
                #当背包容量小于物品i体积时时,显然不可能存在物品i被装入的方案
                if j <self.items[i-1][1]:
                    self.matrix[i][j]=self.matrix[i-1][j]
                else:
                    if self.matrix[i-1][j]>=self.matrix[i-1][j-self.items[i-1][1]]+self.items[i-1][0]:
                        self.matrix[i][j]=self.matrix[i-1][j]
                    else:
                        self.matrix[i][j] = self.matrix[i-1][j-self.items[i-1][1]]+self.items[i-1][0]
        print(self.matrix)
      #仅给出一种方案,有空余时间的读者可以按照本人的思路尝试使用广度优先的方式得到所有最佳解
    def get_the_best_idea(self):
        idea=[]
        node=self.matrix[self.num,self.capacity]
        j=self.capacity
        for i in range(self.num,0,-1):
            if node==self.matrix[i-1][j]:
                node=self.matrix[i-1][j]
                break
            else:
                idea.insert(0,i)
                j-=self.items[i-1][1]
                node=self.matrix[i-1][j]
        idea=np.array(idea)
        idea=idea

        return idea

测试

测试数据集(同程振波老师的MOOC)

物品价值体积
143
254
365

测试截图

在这里插入图片描述

测试结论

可见我们成功的实现了用二维动态规划解决01背包问题

测试结论

可见我们成功的实现了用二维动态规划解决01背包问题

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值