'''
有n件物品和容量為m的揹包 給出i件物品的重量以及價值
求解讓裝入揹包的物品重量不超過揹包容量 且價值最大 。
'''def knapsack(n, w, wts, val):
# dp[i][j]表示當揹包容量為j的情況下,在前i個物品中挑選部分放入揹包能得到的最大價值
dp = [[0] * (w+1) for _ in range(n+1)]
# n遍歷考慮前n個物品是否加入揹包中
for n in range(1, n+1):
# w遍歷揹包的容量
for w in range(1, w+1):
# 揹包剩餘空間不足
if w - wts[n-1] < 0:
dp[n][w] = dp[n - 1][w]
# i. 當第n個物品不選時,dp值與第n-1次的dp值相同
# ii.當第n個物品選擇時,dp值為第n-1次中揹包剩餘容量為【w - wts[n-1]】的dp值
# 加上第n個物品的價值
else:
dp[n][w] = max(dp[n - 1][w - wts[n-1]] + val[n-1], dp[n - 1][w])
return dp[n][w]
使用滾動陣列的思想,去掉第一維
def knapsack_space_optimize(n, w, wts, val):
dp = [0] * (w + 1)
for n in range(n):
# 限制下界,防陣列越界
# 逆序是防止覆蓋n-1次的結果
for w in range(w, wts[n] - 1, -1):
dp[w] = max(dp[w], dp[w-wts[n]] + val[n])
return dp[w]
對於w逆序操作的理解:在考慮第n個物品時, w的逆序遍歷過程中,dp[w]表示的是n-1次時dp[n-1][w]的結果,dp[w-wts[n]]表示的是n-1次時dp[n-1][w-wts[n]]的結果.
# 測試用例
input:
n = 3
w = 4
wts = [2, 1, 3]
val = [4, 2, 3]
output:
6
0-1揹包類似問題:leetcode 416.分割等和子集
class solution(object):
def canpartition(self, nums):
""":type nums: list[int]
:rtype: bool
"""sums = sum(nums)
if sums % 2 == 1:
return false
half = sums // 2
dp = [false] * (half + 1)
# 目標為0時,只要乙個數字都不取就總是能達到的
dp[0] = true
for i in range(len(nums)):
for j in range(half, 0, -1):
# 防陣列越界
if j - nums[i] >= 0:
# 只要有一種情況是可以組成和為half那麼就賦值為true,使用or
dp[j] = dp[j] or dp[j - nums[i]]
return dp[half]
完全揹包問題:leetcode 518.零錢兌換ii
class solution(object):
'''空間:o(n*amount)
'''def change(self, amount, coins):
dp = [[0] * (amount+1) for _ in range(len(coins)+1)]
# 當amount為0時,無為而治,解決方法為1
for i in range(len(coins)+1):
dp[i][0] = 1
for i in range(1, len(coins)+1):
for j in range(1, amount+1):
# 這裡的 i-1 非常容易忽略,這裡i表示使用第i中硬幣,但是對應在陣列裡的索引是i-1
if j-coins[i-1] >= 0:
# 目標是求硬幣所有組合可能情況,所以要加起來
dp[i][j] = dp[i-1][j] + dp[i][j-coins[i-1]]
else:
dp[i][j] = dp[i-1][j]
return dp[len(coins)][amount]
'''空間優化:滾動陣列
空間:o(amount)
'''def change_optim(self, amount, coins):
dp = [0] * (amount+1)
dp[0] = 1
for i in range(len(coins)):
# 這裡不需要逆序
for j in range(1, amount+1):
if j-coins[i] >= 0:
dp[j] = dp[j] + dp[j-coins[i]]
return dp[amount]
DP 揹包系列問題 有依賴的揹包問題
有依賴的揹包問題又是乙個經典的揹包延伸問題,理解她可以讓我們更深刻地理解揹包中三重迴圈的順序邏輯,同時她也是樹形動規的雛形。題目一般情形 有 n nn 個物品和乙個容量是 v vv 的揹包。物品之間具有依賴關係,且依賴關係組成一棵樹的形狀。如果選擇乙個物品,則必須選擇它的父節點。每件物品的編號是 i...
動態規劃 揹包問題(DP系列)
一 問題描述 有n 個物品,它們有各自的重量和價值,現有給定容量的揹包,如何讓揹包裡裝入的物品具有最大的價值總和?二 總體思路 根據動態規劃解題步驟 問題抽象化 建立模型 尋找約束條件 判斷是否滿足最優性原理 找大問題與小問題的遞推關係式 填表 尋找解組成 找出01揹包問題的最優解以及解組成,然後編...
DP 揹包問題
大牛 以下使用滾到陣列 若輸入要求一般,可以邊定義狀態邊輸入,不需儲存 memset f,0,sizeof int n 若求最小值,除 f 0 其餘初始化為 inf,f 0 0是必須的 求最大最小都一樣 確保有從無到有的起點 0 1揹包 一般形式 f i v max f i 1 v f i 1 v ...