[算法][動態規劃]揹包問題變體-均分禮物

均分禮物

今天遇到的一個面試手撕題:

給定一個禮物價值清單,需要將其進行劃分爲兩個子集,以使得兩個子集的價值和的差值最小。

思路

[算法][動態規劃][揹包問題①]0-1揹包問題的優化及約束變形[python實現

  1. 將其視爲一個0-1揹包問題
  2. 取總價值的一半作爲揹包容量
  3. 儘量填滿這個揹包(此問題中wiw_i=viv_i)

dp[j]=max{dp[jwi]+vi,dp[j]}dp[j]=max\{dp[j−w_i]+v_i ,dp[j]\}

  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]
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章