完全揹包和0-1揹包的區別在於每個物品可以選擇多次,也是通過畫表可以方便得到轉移方程。
其實狀態的轉移無論是target在外迴圈還是內迴圈,都不會出現3 = 【1,2】,【2,1】的情況。
0/1揹包
定義:物品只能用一次
dp[i][j] = max(dp[i-1][j], dp[i-1][j-weight[i]] + value[i])
完全揹包
定義:物品可以用無限次
dp[i][j] = max(dp[i-1][j], dp[i][j-weight[i]] + value[i])
比較的是第i行前面的dp[i][j-weight[i]],因為前面的已經都是最佳的多次選擇的case,針對某乙個物品,可以多次選擇,此時前面的j已經安排好了,所以此時必須使用的是第i行前面的j,而不是0-1揹包的i-1行,因為滿足weight是j的最佳的配置已經更新到了第i行。
由二維轉一維也是同樣的道理。
0/1揹包
定義:物品只能用一次
for i in range(n):
for j in range(amount, -1, -1):
dp[j] = max(dp[j], dp[j-weight[i]] + value[i])
因為此時第i行必須使用的是第i-1行的結果,所以倒序的話就不會使得後面要使用的提前改變了。
完全揹包
定義:物品可以用無限次
for i in range(n):
for j in range(amount+1):
dp[j] = max(dp[j], dp[j-weight[i]] + value[i])
因為此時需要使用的第i行的結果,所以直接使用順序進行。與上述對比。
給定不同面額的硬幣 coins 和乙個總金額 amount。編寫乙個函式來計算可以湊成總金額所需的最少的硬幣個數。如果沒有任何一種硬幣組合能組成總金額,返回 -1。
你可以認為每種硬幣的數量是無限的。
示例 1:
輸入:coins = [1, 2, 5], amount = 11
輸出:3
解釋:11 = 5 + 5 + 1
示例 2:
輸入:coins = [2], amount = 3
輸出:-1
class
solution
:def
coinchange
(self, coins: list[
int]
, amount:
int)
->
int:
# 完全揹包問題
n =len(coins)
if amount <=0:
return
0 nums = coins
dp =
[amount+1]
*(amount+1)
for i in
range
(n):
dp[0]
=0for i in
range(0
, n)
:for j in
range(1
, amount+1)
:if j - nums[i]
>=0:
dp[j]
=min
(dp[j-nums[i]]+
1, dp[j]
)if dp[-1
]== amount +1:
return-1
else
:return dp[-1
]
對於amount類的,還是設定長度為amount+1,0處設定為初始狀態~~
如果是用二維的陣列轉移公式來表示則為:dp[i][j]表示使用前i枚硬幣組成價值為j,至少需要多少枚硬幣。
dp[i][j] = min(dp[i][j-nums[i]]+1, dp[i-1][j]), j - nums[i] >= 0
dp[i][j] = dp[i-1][j] , j-nums[i] < 0
一維陣列的轉移:
dp[j] = min(dp[j], dp[j-nums[i]]+1), j-nums[i] >= 0----注意可以重複使用硬幣,i在外迴圈,j在內迴圈。
dp[j] = dp[j], j-nums[i] < 0
組合的題目還分組合能否重合[1,1,2]和[2,1,1]是否相同,正常是相同的,除非特殊交代~~
dp[i][j] = dp[i-1][j] + dp[i][j-nums[i]] ----i-1枚硬幣湊成j的組合數加上i枚硬幣湊成j-nums[i]的組合數,就可以得到總的。
dp[i][j] = dp[i-1][j], j-nums[i] < 0
特別注意一下初始條件,全部不選擇也是乙個組合,dp[i][0] = 1
注意這裡並沒有組合數的+1,特別是dp[i][j-nums[i]],並沒有增加組合數···
因為這是個組合問題,我們不關心硬幣使用的順序,而是硬幣有沒有被用到。是否使用第k個硬幣受到之前情況的影響。可以對比下面的爬樓梯,爬樓梯是排列問題~~~
class
solution
:def
change
(self, amount:
int, coins: list[
int])-
>
int:
ifnot amount:
###注意,amount為0的情況下是1,全部選擇數為0也是乙個選擇
return1if
not coins:
return
0 dp =
for i in
range(1
+len
(coins)):
[0]*
(amount+1)
)# 只要滿足了減到0,那麼就是1了,在1的基礎上,dp[1] = dp[0]
for i in
range(1
+len
(coins)):
dp[i][0
]=1for i in
range(1
,len
(coins)+1
):for j in
range(1
, amount+1)
:# 二維兩者可以顛倒,但是一維不行!!
每次可以爬多少階,也就是硬幣的型別~~但是這裡是排列,可以重複。
class
solution
:def
climbstairs
(self, n:
int)
->
int:
dp =[0
]*(n+1
) dp[0]
=1for i in
range(1
, n+1)
:if i -
2>=0:
dp[i]
= dp[i-1]
+ dp[i-2]
else
: dp[i]
= dp[i-1]
return dp[-1
]
擴充套件成每次可以爬steps的階梯:
class
solution
:def
climbstairs
(self, n:
int)
->
int:
dp =[0
]*(n+1
) dp[0]
=1for i in
range(1
, n+1)
:if i -
2>=0:
dp[i]
= dp[i-1]
+ dp[i-2]
else
: dp[i]
= dp[i-1]
return dp[-1
]
揹包問題(完全揹包)
1.矩陣鏈乘法 2.投資組合問題 3.完全揹包問題 4.01揹包問題 5.最長公共子串行 乙個揹包,可以放入n種物品,物品j的重量和價值分別為,如果揹包的最大重量限制是b,怎麼樣選擇放入揹包的物品以使得揹包的總價值最大?組合優化問題,設表示裝入揹包的第j個物品的數量,解可以表示為。那麼目標函式和約束...
完全揹包問題
這個是從ppt上弄過來的。完全揹包問題 有n種物品和乙個容量為v的揹包,每種物品都有無限件可用。放入第i種物品的耗費的空間是ci,得到的價值是wi。求解 將哪些物品裝入揹包,可使這些物品的耗費的空間總和不超過揹包容量,且價值總和最大 基本思路 這個問題非常類似於01揹包問題,所不同的是每種物品有無限...
完全揹包問題
設有n種物品,每種物品有乙個重量及乙個價值。但每種物品的數量是無限的,同時有乙個揹包,最大載重量為m,今從n種物品中選取若干件 用乙個物品可以多次選取 使其重量的和小於等於m,而價值的和為最大。輸入有多組資料,對於每組輸入資料第1行 兩個整數,m 揹包容量,m 200 和n 物品數量,n 30 第2...