揹包問題 416 分割等和子集

2021-10-09 04:12:22 字數 3335 閱讀 2166

0-1揹包問題。

dp陣列中dp[i][w]的含義。

dp[i][w]的定義如下:對於前i個物品,當前揹包的容量為w,這種情況下可以裝的最大價值是dp[i][w]。

如果你沒有把這第i個物品裝入揹包,那麼很顯然,最大價值dp[i][w]應該等於dp[i-1][w]。

如果你把這第i個物品裝入了揹包,那麼dp[i][w]應該等於dp[i-1][w-wt[i-1]] + val[i-1]。

首先,由於i是從 1 開始的,所以對val和wt的取值是i-1。

而dp[i-1][w-wt[i-1]]也很好理解:你如果想裝第i個物品,你怎麼計算這時候的最大價值?

換句話說,在裝第i個物品的前提下,揹包能裝的最大價值是多少?

顯然,你應該尋求剩餘重量w-wt[i-1]限制下能裝的最大價值,加上第i個物品的價值val[i-1],

這就是裝第i個物品的前提下,揹包可以裝的最大價值。

給你乙個可裝載重量為w的揹包和n個物品,每個物品有重量和價值兩個屬性。

其中第i個物品的重量為wt[i],價值為val[i],現在讓你用這個揹包裝物品,最多能裝的價值是多少?

舉個簡單的例子,輸入如下:

n = 3, w = 4

wt = [2, 1, 3]

val = [4, 2, 3]

演算法返回 6,選擇前兩件物品裝進揹包,總重量 3 小於w,可以獲得最大價值 6。

# 0-1揹包問題

import sys

wt =[2

,1,3

]val =[4

,2,3

]n =

3w =

4# dp[i][j]表示,對於前i個物品,當前揹包的容量為j時,揹包可以裝的最大價值,

# 為w+1而不是w表示揹包容量從0開始

dp =[[

0for _ in

range

(w+1)]

for _ in

range

(n+1)]

for i in

range(1

, n+1)

:for j in

range(1

, w+1)

:# 當揹包容量裝不下時,只能選擇不裝,所以和之前大小一樣

if j - wt[i-1]

<0:

dp[i]

[j]= dp[i-1]

[j]else

:# 選擇不裝入揹包和裝入揹包,看哪個更優

# 剩餘重量w-wt[i-1]限制下能裝的最大價值,加上第i個物品的價值val[i-1],

dp[i]

[j]=

max(dp[i-1]

[j], dp[i-1]

[j - wt[i -1]

]+ val[i-1]

)print

(dp[-1

][-1

])

import sys 

# 重量

wt =[2

,1,3

]# 價值

val =[4

,2,3

]# 物品個數為n

n =3

# 揹包容量為w

w =4

# dp[i][j]表示,對於前i個物品,當前揹包的容量為j時,揹包可以裝的最大價值,

# 為w+1而不是w表示揹包容量從0開始

dp =[0

for _ in

range

(w+1)]

for i in

range

(n):

for j in

range

(w, wt[i]-1

,-1)

: dp[j]

=max

(dp[j]

, dp[j - wt[i]

]+ val[i]

)print

(dp[-1

])

給定乙個只包含正整數的非空陣列。是否可以將這個陣列分割成兩個子集,使得兩個子集的元素和相等。

注意:每個陣列中的元素不會超過 100

陣列的大小不會超過 200

示例 1:

輸入: [1, 5, 11, 5]

輸出: true

解釋: 陣列可以分割成 [1, 5, 5] 和 [11].

示例 2:

輸入: [1, 2, 3, 5]

輸出: false

解釋: 陣列不能分割成兩個元素和相等的子集.

class

solution

:def

canpartition

(self, nums: list[

int])-

>

bool

: n =

len(nums)

w =sum(nums)

if w%2==

1:return

false

w //=

2# dp[i][j]表示 在載重量為j的情況下,如果前i個元素能夠將揹包放滿,

# 則dp[i][j] = true,如果不能夠放滿,則dp[i][j] = false。

dp =[[

false]*

(w +1)

for _ in

range

(n +1)

]# 初始化base case :dp[...][0] = true,相當於當載重量為0的時候,

# 肯定什麼東西也不用放,揹包肯定預設是滿的,因為載重量為0嘛,所以是true;

# dp[0][...] = false,相當於在任一載重量時,什麼東西都不放,那肯定揹包沒有滿,所以是false

for i in

range

(n+1):

dp[i][0

]=true

nums =[0

]+ nums

for i in

range(1

, n+1)

:for j in

range(1

, w+1)

:if nums[i]

<= j:

dp[i]

[j]= dp[i-1]

[j]or dp[i-1]

[j-nums[i]

]else

: dp[i]

[j]= dp[i-1]

[j]return dp[-1

][-1

]

0 1揹包問題 416 分割等和子集

1 狀態 揹包容量 可選擇的物品 2 選擇 裝或者不裝 3 定義dp陣列 dp i j x,前i個物品,容量為j時的揹包。x為true false 4 初始化 在沒有任何物品裝入時的合法狀態 要求恰好裝滿 dp i 0 只有容量為0的揹包才能滿足 沒有要求恰好裝滿 dp 0 i 即沒有任何物品放入 ...

416 分割等和子集

給定乙個只包含正整數的非空陣列。是否可以將這個陣列分割成兩個子集,使得兩個子集的元素和相等。注意 每個陣列中的元素不會超過 100 陣列的大小不會超過 200 示例 1 輸入 1,5,11,5 輸出 true 解釋 陣列可以分割成 1,5,5 和 11 示例 2 輸入 1,2,3,5 輸出 fals...

416 分割等和子集

主要題目中說了不超過100個數字,數字都不超過200。所以可能的和不會超過20000,這個量級對計算機來說不算大,所以考慮用dp考察每個可能的和是否存在。class solution int sum accumulate nums.begin nums.end 0 if sum 1 int siz ...