動態規劃之揹包問題–python版本
問題
已知一個最大量的揹包,給定一組給定固定價值和固定體積的物品,求在不超過最大值的前提下,能放入揹包中的最大總價值。
解題思路
該問題是典型的動態規劃問題,分爲三種不同的類型(0-1揹包問題、完全揹包和多重揹包問題)
解題關鍵–狀態轉移表達式:
- k表示總共物品爲k件
- C表示揹包總容量
- 表示第i件物品佔用容量
- 表示第i件物品價值
0-1揹包
from _ctypes import Array
class Knapsack:
c: Array = [0, 2, 5, 4, 3, 6] # capacity 各個物品容量
v: Array = [0, 3, 4, 6, 7, 6] # value權值
f: Array = [0 for i in range(0, 21)] # 存放結果 需要初始化,否則數組會越界
def bag_1(self, capacitySum):
'''
通俗算法
時間複雜度:O(capacitySum * n)
空間複雜度:O(capacitySum * n)
:param capacitySum: 包的總容量
:return: 返回求解的數組的
'''
n = len(self.c)
res = [[0 for col in range(21)] for row in range(n)]
for i in range(1, n):
for j in range(1, capacitySum + 1):
if self.c[i] > j:
res[i][j] = res[i - 1][j]
else:
# 當前狀態爲 前一個狀態最優解 與 選取第i件商品的價值和剩餘空間最優解 的最大值
res[i][j] = max(res[i - 1][j], res[i - 1][j-self.c[i]] + self.v[i])
return res
def bag(self, capacitySum):
'''
優化空間算法
時間複雜度:O(capacitySum * n)
空間複雜度:O(capacitySum * 1)
:param capacitySum: 包的總容量
:return: 返回求解的數組的
'''
n = len(self.c)
for i in range(1, n):
# 此處爲倒敘,正序在計算過程中不能表示上一個狀態的值,被更新啦
for j in range(capacitySum, self.c[i] - 1, -1):
self.f[j] = max(self.f[j], self.f[j - self.c[i]] + self.v[i])
return self.f
完全揹包
完全揹包問題是指每種物品都有無限件
from _ctypes import Array
class Knapsack:
c: Array = [0, 2, 5, 4, 3, 6] # capacity 各個物品容量
v: Array = [0, 3, 4, 6, 7, 6] # value權值
f: Array = [0 for i in range(0, 21)] # 存放結果 需要初始化,否則數組會越界
def bag_complete(self, capacitySum):
'''
優化空間算法
時間複雜度:O(capacitySum * n)
空間複雜度:O(capacitySum * 1)
:param capacitySum: 包的總容量
:return: 返回求解的數組的
'''
n = len(self.c)
for i in range(1, n):
# 此處爲正序,完全揹包需要是當前揹包的最優解,必須從頭開始
# 從c[i]開始,因爲i前面的最優解,直接照抄 而同一個數組不需要變化
for j in range(self.c[i], capacitySum + 1):
self.f[j] = max(self.f[j], self.f[j - self.c[i]] + self.v[i])
return self.f
多重揹包問題
多重揹包問題限定了一種物品的個數,解決多重揹包問題,只需要把它轉化爲0-1揹包問題即可。比如,有2件價值爲5,重量爲2的同一物品,我們就可以分爲物品a和物品b,a和b的價值都爲5,重量都爲2,但我們把它們視作不同的物品。
參考
[Algorithm][011] 動態規劃 Dynamic Programming(DP) 揹包DP 3講 [OTTFF]