跟随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()