完全揹包問題

2021-10-14 04:16:32 字數 4446 閱讀 4716

完全揹包和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...