跟随carl代码随想录刷题
语言:python
动态规划从小问题着手,逐步解决大问题。解决的子问题(小问题)会帮助我们解决大问题。
动态规划五部曲
确定dp数组(dp table)以及下标的含义
dp[i][j]
表示从下标为(0, i)的物品
里面任意取,放进容量为j
的背包,价值总和是d[i][j]
。⭐️确定状态转移公式(递推公式)
dp[i][j] = max(dp[i-1][j], dp[i-1][j - weight[i] + value[i]])
# 包括两个方向dp数组如何初始化
dp[i][0] = 0
# 如果背包重量为0,那价值永远为0for j in range(bagweight): dp[0][j] = value[0]
# 当背包容量≥
第一个物体的重量时,第一行价值均为第一个物品的重量确定遍历顺序
举例推导dp数组
def test_2D_bag_problem1(bag_size, item_weight, item_value) -> int:
rows, cols = len(item_weight), bag_size + 1
dp = [[0 for _ in range(cols)] for _ in range(rows)]
# 初始化dp数组
# 初始化第一列
for i in range(rows):
dp[i][0] = 0
first_item_weight, first_item_value = item_weight[0], item_value[0]
# 初始化第一行
for j in range(1, cols):
if first_item_weight <= j: # 如果物品的重量比背包容量小,那么就添加其价值
d[0][j] = first_item_value
# 更新dp数组:先遍历物品,再遍历背包
for i in range(1, len(item_weight)):
cur_weight, cur_val = item_weight[i], item_value[i]
for j in range(1, cols):
if cur_weight > j: # 如果当前物品的重量大于背包容量
dp[i][j] = dp[i - 1][j] # 不装,保持原价值
else:
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - cur_weight] + cur_val)
# dp[i - 1][j - cur_weight]表示:当容量等于[j - cur_weight]时的价值
# dp[i - 1][j - cur_weight] + cur_val表示:装入现有物品之后的价值
print(dp)
if __name__ == "__main__":
bag_size = 4
item_weight = [1, 3, 4] # 各个物品的重量
item_value = [15, 20, 30]
test_2D_bag_problem1(bag_size, wight, value)
上述过程也可以用一维数组来做,也就是:
遍历顺序:背包容量从大到小,保证物品i只被放入一次。
覆盖
问题,所以只能背包容量从大到小
遍历。
(背包容量, 当前物品的重量, -1(逆序))
,也就是说,如果背包容量<当前物品的重量
,就不遍历(不做更改),保留原值×
表示不遍历】覆盖
问题,所以可以背包容量从小到大遍历
。def test_2D_bag_problem1() -> int:
bag_size = 4
item_weight = [1, 3, 4] # 各个物品的重量
item_value = [15, 20, 30]
# 初始化:全为0
dp = [0] * (bag_size + 1)
# 先遍历物品,再遍历背包容量
for i in range(len(item_weight)):
for j in range(bag_weight, item_weight[i] - 1, -1):
# 递归公式
dp[j] = max(dp[j], dp[j - item_weight[i]] + item_value[i])
print(dp)
test_1_wei_bag_problem()
多重背包的意思就是:每个物品有多件,求当背包容量一定时,能装入的最大价值是多少。我们可以把多件相同的物品
摊开来看,其实就是01背包问题
。可以转化为01背包问题来做。多重背包问题了解到这儿就可以了,没有对应的题目练习。
def test_multi_pack1():
'''版本一:改变物品数量为01背包格式'''
weight = [1, 3, 4]
value = [15, 20, 30]
nums = [2, 3, 2]
bag_weight = 10
for i in range(len(nums)):
# 将物品展开数量为1
while nums[i] > 1:
weight.append(weight[i])
value.append(value[i])
nums[i] -= 1
dp = [0]*(bag_weight + 1)
# 遍历物品
for i in range(len(weight)):
# 遍历背包
for j in range(bag_weight, weight[i] - 1, -1):
dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
print(" ".join(map(str, dp)))