均分禮物
今天遇到的一個面試手撕題:
給定一個禮物價值清單,需要將其進行劃分爲兩個子集,以使得兩個子集的價值和的差值最小。
思路
- 將其視爲一個0-1揹包問題
- 取總價值的一半作爲揹包容量
- 儘量填滿這個揹包(此問題中=)
- 總價值減去半揹包的最優價值即可
代碼
class Solution:
def maxPresent(self , presentVec):
# 把總體積的一半作爲揹包容量
all_volume = sum(presentVec)
half_volume = all_volume//2
dp = [0] * (half_volume+1)
for w in presentVec:# 第i個物品
for j in range(half_volume, w-1, -1):
dp[j] = max(dp[j], w + dp[j-w])
return all_volume - 2*dp[-1]
如果要求應對輸出兩個子集中具體物品內容:
class Solution:
def maxPresent(self , presentVec ):
# 把總體積的一半作爲揹包容量
all_volume = sum(presentVec)
half_volume = all_volume//2
dp = [0] * (half_volume+1)
trace = [[] for _ in range(half_volume + 1)] # 添加一個軌跡
for w in presentVec:# 第i個物品
for j in range(len(dp)-1, w-1, -1):
new_price = w + dp[j-w]
if new_price > dp[j]:
dp[j] = new_price
trace[j] = trace[j-w] + [w] # 重寫軌跡
return all_volume - 2*dp[-1], trace[-1] # 最小差值和其中一個子集
測試:
s = Solution()
print(s.maxPresent([41,467,334,1,169,224,478,358]))
# 最小差值爲0,其中一個子集爲:[334, 224, 478]