01揹包問題 二維dp
https://programmercarl.com/揹包理論基礎01揹包-1.html
影片講解:https://www.bilibili.com/video/BV1cg411g7Y6
有n件物品和一個最多能背重量為w 的揹包。第i件物品的重量是weight[i],得到的價值是value[i] 。每件物品只能用一次,求解將哪些物品裝入揹包裡物品價值總和最大。
思考
dp[i][j] 表示從下標為[0-i]的物品裡任意取,放進容量為j的揹包,價值總和最大是多少。
def test_2_wei_bag_problem1():
weight = [1, 3, 4]
value = [15, 20, 30]
bagweight = 4
# 二維陣列
dp = [[0] * (bagweight + 1) for _ in range(len(weight))]
# 初始化
for j in range(weight[0], bagweight + 1):
dp[0][j] = value[0]
# weight陣列的大小就是物品個數
for i in range(1, len(weight)): # 遍歷物品
for j in range(bagweight + 1): # 遍歷揹包容量
if j < weight[i]:
dp[i][j] = dp[i - 1][j]
else:
dp[i][j] = max(dp[i - 1][j], dp[i - 1][j - weight[i]] + value[i])
print(dp[len(weight) - 1][bagweight])
test_2_wei_bag_problem1()
01揹包問題 一維dp
https://programmercarl.com/揹包理論基礎01揹包-2.html
影片講解:https://www.bilibili.com/video/BV1BU4y177kY
思考
在一維dp陣列中,dp[j]表示:容量為j的揹包,所背的物品價值可以最大為dp[j]。
思考
使用滾動陣列,先物品再揹包。揹包遍歷需要逆序,正序的話上一層的左側值就被覆蓋了,無法滾動。
def test_1_wei_bag_problem():
weight = [1, 3, 4]
value = [15, 20, 30]
bagWeight = 4
# 初始化
dp = [0] * (bagWeight + 1)
for i in range(len(weight)): # 遍歷物品
for j in range(bagWeight, weight[i] - 1, -1): # 遍歷揹包容量
dp[j] = max(dp[j], dp[j - weight[i]] + value[i])
print(dp[bagWeight])
416. 分割等和子集
本題是 01揹包的應用類題目
https://programmercarl.com/0416.分割等和子集.html
影片講解:https://www.bilibili.com/video/BV1rt4y1N7jE
思考
暴力回溯太費事了。
轉換為01揹包問題。揹包容量為sum/2,物品重量為nums[i],價值也是nums[i]
dp[i] 揹包容量i是否可以裝滿
class Solution:
def canPartition(self, nums: List[int]) -> bool:
if len(nums)==1:
return False
sum_ = sum(nums)
if sum_ % 2 !=0:
return False
k = int(sum_ / 2)
# dp[i] 揹包容量i是否可以裝滿
dp = [False] * (k+1)
dp[0] = True
for num in nums:
for i in range(k,0,-1):
if i>=num:
dp[i] = dp[i] or dp[i-num]
return dp[k]