DP 揹包問題系列python

2021-10-09 21:37:53 字數 2783 閱讀 2020

'''

有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 ...