Python 刷題筆記 揹包問題

2021-10-06 06:58:27 字數 2791 閱讀 9067

刷動態規劃的第二天,有些自閉,剛靠著大魔王的歌緩過來了。關於動態規劃,我還處於看題解時哦哦哦、看題目時???的階段,所以整理的點不深。除了昨天推給大家的鏈結,今天也是發現了一位刷題大牛的寶藏,不僅動態規劃,各類演算法都做了整理、引導,屬實 respect !

動態規劃專題

關於動態規劃,我現階段的理解是在窮舉的過程中找到可以復用的求值過程,或者說找到當前要求的值與已經求好值之間的關係,建立所謂的「狀態轉移方程」。具體的講解我等之後理解加深有機會再展開,刷題階段效率為主,今天記錄兩道揹包題目。

0-1揹包問題描述

現在有乙個可裝載重量為 w 的揹包和 n 個物品,每個物品有重量和價值兩個屬性。其中第 i 個物品的重量為 wt[i],價值為 val[i],現在讓你用這個揹包裝物品,最多能裝的價值是多少?

例如:

w = 10, n = 5

wt =

[2, 2, 6, 5, 4]

val =

[6, 3, 5, 4, 6]

返回 15,因為可以裝 [2,2,4] 重量的物品,價值分別 [6,3,6]

題目中 0-1 指的是揹包裝物品時,要麼裝整個物品、要麼不裝,不能只裝取部分。

因為揹包有重量限制,所以當我們遍歷物品時,無法確定物品是否被裝入揹包,就更難以找到裝某一物品時與之前狀態的關聯。動態規劃會強調「狀態」,通過自定義的一維或二維陣列為我們將物品裝入揹包這個行為定義成狀態的變化,從而找到與上一次裝物品之間的關聯。

動態規劃英文 dynamic programming,所以定義相關的狀態陣列多用 dp, 本題目中就是通過定義二維陣列、在 python 中即巢狀列表來實現。

揹包問題中,用 dp [ i ] [ j ] 表示在物品列表中的前 i 件物品操作完、此時揹包容量為 j 的狀態下,揹包所能裝的最大價值,恰好對應了題目所求,求容量為 w 的揹包、 n 個物品所實現最大價值即 dp [ n ] [ w ] 對應的值。

為何要定義這麼乙個奇怪的狀態呢?就是為了找尋裝物品時不同狀態間的關係,從而建立狀態轉移方程。在裝第 i 件物品時,對應題目中的重量和價值列表,該物品重量為 wt[i-1]、價值為 val[i-1]。

在操作這第 i 件物品之前,揹包狀態處於 dp [ i-1 ] [ j ] ,物品 -1、容量不變。進行到第 i 件了,要麼裝、要麼不裝就這兩種選擇:裝的話,新的狀態要在之前的價值上新增新物品的價值;不裝的話,那麼新狀態與之前狀態的價值是相等的。這便是揹包問題狀態轉移關鍵所在。有種建立遞迴關係的意思,所以要找到初始狀態值,在 i = 0 或 j = 0 時,乙個是 0 件物品、乙個是揹包容量為 0,其價值對應為 0。之後的狀態值在此基礎上可以不斷找到得出。

因為本題不是 leetcode 原題,所以解法**沒有沿用 class 那種格式,只是定義了函式:

# n 對應個數,c 對應揹包容量,w 為物品重量列表,v 物品價值列表

defbag_value

(n,c,w,v)

:# 巢狀的列表解析式生成 c x n 的二維陣列、列表

dp =[[

none

for j in

range

(c+1)]

for i in

range

(n+1)]

# 為初始狀態 i=0 或 j=0 時賦值 0

for i in

range

(n+1):

for j in

range

(c+1):

if i ==0:

dp[i]

[j]=

0if j ==0:

dp[i]

[j]=

0# 仍然遍歷二維陣列

for i in

range(1

,n+1):

for j in

range(1

,c+1):

# 若揹包容量小於要裝的物品重量,那麼該物品不會被裝入、狀態不變

if j: dp[i]

[j]= dp[i-1]

[j]# 若有可能裝該物品,取裝或不裝該物品狀態下最大價值

else

: dp[i]

[j]=

max(dp[i-1]

[j-w[i-1]

]+v[i-1]

,dp[i-1]

[j])

# 最終返回 n、c 值下的 dp 價值

return dp[n]

[c]n =

5c =

10w =[2

,2,6

,5,4

]v =[6

,3,5

,4,6

]result = bag_value(n,c,w,v)

# 可以得到 result 值為 15

這裡值得注意的是,在不確定是否裝該物品時,對上乙個狀態的取值並沒有取我們之前提到的 dp [ i-1 ] [ j ] 而是對這裡的揹包容量處理、調整至最大容量減去第 i 件物品的重量,這是為了保證裝完該物品後不超出揹包容量限制,而 dp 本身對揹包容量是有遍歷的,所以選取的是最精準的上一狀態。

刷題刷到動態規劃,很大的感受是我這刷題實施得太晚了,早幾年就好了,之前對這些概念、演算法完全沒有意識。現在補過,只能說好過之後來補。

同時,潛意識裡就覺著動態規劃很難,所以選的策略是跳出題目,看有經驗大牛的整理專題,在他們的引領下熟悉這些題目的套路,先學習、掌握要點後再通過練習來提高熟練度。

今天看這型別的題目看的腦袋大,就簡單記這麼些吧,明兒見~

刷題之路 揹包問題

乙個揹包有一定的承重cap,有n件物品,每件都有自己的價值,記錄在陣列v中,也都有自己的重量,記錄在陣列w中,每件物品只能選擇要裝入揹包還是不裝入揹包,要求在不超過揹包承重的前提下,選出物品的總價值最大。給定物品的重量w價值v及物品數n和承重cap。請返回最大總價值。經典動態規劃問題,類似於找零錢問...

python揹包問題 揹包問題Python

題目 揹包容量ba 物品thing v 問題 1.是否可以裝滿揹包2.裝滿揹包最少需要多少件物品3.裝滿揹包最多需要多少件物品4.該揹包最多一共可以裝多重的物品5.裝滿揹包一共有多少種方案 就算物品重量一樣,但也是不同的方案 一 01揹包 def bag 01 bag v,thing v 是否可以裝...

刷題心得 揹包問題的列舉方式

以0 1揹包為例,到底正序列舉還是倒序列舉?正序列舉還是倒敘列舉的原則取決於0 1揹包的性質,即乙個階段的狀態 1個物品 不能被放進揹包兩次。如果正序列舉的話,當前階段被上乙個階段更新,而下乙個階段仍然可能被上乙個階段更新。多以就相當於乙個物品被放進了揹包兩次。違背0 1揹包的規則。而完全揹包就不需...