01背包问题求解

来源于 https://kamacoder.com/problempage.php?pid=1046

使用动态规划,五步走

1.定义状态数组和具体状态含义:

dp是个二维数组,第一维代表物品索引,第二维代表背包空间状态。
dp[i][j]是指物品i 在背包空间j 的情况下所能放的最大价值。

2.明确状态转移公式

根据题意,要么我放物品i ,要么不放。由易到难:

先考虑不放,那一定是我背包空间不够这个物品的体积才不放。所以此时dp[i][j] 的状态转移就是继承在背包空间j 的时候,物品i-1 (也就是上一个物品)时刻的状态: dp[i][j] = dp[i-1][j]

再考虑放,放的话首先要加上物品i 的价值,然后继承上一个能和物品i 的体积适配(也就是背包空间j去掉物品i 的体积后所剩的背包空间,在这个背包空间j-weigths[i-1]下的前一个物品i-1所得到的最大价值)的状态: dp[i][j] = dp[i-1][j-weigths[i-1]] + values[i-1]
这里为什么不是继承前一个物品在空间j下的状态,因为这样很可能两个物品加起来背包塞不下,为了尝试在物品i 时能成功塞到空间j 里,必须继承背包空间j-weigths[i-1]时的状态。

综合下,能够放的情况下,我也可以不放,这样就省了空间,有可能在后面有更有价值的。
所以考虑放的情况下也是放与不放取最大值。

问:为什么明明是物品i,空间j,但是每次都是weigths[i-1]、values[i-1]?
答:这与dp初始化有关,我在初始化时考虑了物品0和空间0,都代表不存在。但是weigths是列表,访问物品1的时候索引是0,物品0是不存在的。

问:什么是背包空间不够这个物品的体积?
答:如果空间j < weights[i-1],说明物品i 的体积超过了当前空间。

3.初始化边界条件

根据定义,物品i为0时,代表没有物品,所以dp[0][j]=0
空间j为0时,代表没有空间,放不进去,所以dp[i][j]=0

4.遍历方式确定

按照先遍历一维,再遍历二维的方式。先遍历每个物品,再遍历每个背包空间。

5.举例推导dp

在这里插入图片描述

代码

ACM模式


import sys

# 从标准输入读取数据
input = sys.stdin.read
data = input().split()

# 解析第一个整数m(研究材料的种类)和第二个整数n(小明的行李空间)
m, n = int(data[0]), int(data[1])

# 解析研究材料所占空间的列表weights和研究材料价值的列表values
weights = list(map(int, data[2:2 + m]))
values = list(map(int, data[2 + m:2 + 2 * m]))

# 动态规划
# 状态数组dp,dp[i][j]表示前i个物品放入容量为j的背包中可以获得的最大价值
dp = [[0 for _ in range(n + 1)] for _ in range(m + 1)]

# 填充状态数组dp
for i in range(1, m + 1):  # 遍历每一个物品
    for j in range(1, n + 1):  # 遍历背包容量从1到n
        if weights[i - 1] > j:  # 如果当前物品的重量大于当前背包容量
            dp[i][j] = dp[i - 1][j]  # 当前物品不能放入背包,继承上一个状态
        else:
            # 当前物品可以放入背包,选择放入或不放入,取最大值
            dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weights[i - 1]] + values[i - 1])

# 输出dp数组中dp[m][n]的值,即前m个物品放入容量为n的背包中可以获得的最大价值
print(dp[m][n])

      

时间复杂度:O(m * n),因为需要遍历每个物品和每个背包容量。
空间复杂度:O(m * n),因为需要一个二维数组来存储中间结果。

  • 5
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
01背包问题可以通过分支限界法来求解。分支限界法是一种可以用来解决搜索问题的算法,它通过不断地分割搜索空间,逐步确定最优解的方法。 以下是使用分支限界法解决01背包问题的步骤: 1. 初始化 首先,我们需要初始化一个优先队列(priority queue),用于存储搜索状态。队列中的每个元素都包含以下信息: - 当前背包中已经放入的物品的重量和价值; - 目前还没有考虑是否放入的物品的下标; - 当前背包中剩余的容量; - 当前背包中已经放入的物品的总价值; - 当前搜索状态的上界(即当前状态能够达到的最大价值); 我们将初始状态(背包中没有放入任何物品)加入优先队列中。 2. 迭代搜索 接下来,我们开始迭代搜索。每次从队列中取出一个搜索状态,考虑两种情况: - 如果当前搜索状态的上界小于当前已经找到的最优解,那么这个状态就被剪枝,不再考虑; - 否则,我们考虑将下一个物品放入背包中或者不放入背包中两种情况。对于每种情况,我们都可以计算出一个新的搜索状态。如果新状态的上界大于当前已经找到的最优解,那么就将这个状态加入优先队列中。 3. 返回结果 当队列为空时,搜索结束。此时,我们已经找到了最优解,返回最优解的价值。 这就是使用分支限界法解决01背包问题的步骤。这种方法可以大大提高搜索效率,因为它能够通过剪枝来减少搜索空间。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

灵海之森

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值