首先是 01 揹包問題:數組
假設有不少商品每件商品都會佔必定體積 v[x, y, z] (x,y,z是指某種商品佔有的體積) 同時每件商品價值 w[x, y ,z] (對應於v裏的商品所對應的價值)也不徹底同樣,咱們有兩種選擇我拿走或者不拿走,可是個人揹包容量有限不能把全部商品全拿走,怎麼辦才能使得咱們取得商品總的價值最大。app
首先這是一個動態規劃問題,好比設咱們取第n件商品的時候咱們已經算出來取前n件商品的最大價值是f(n),那麼咱們在取第n+1件的時候要麼取走要麼不拿走,也就有兩種狀況 A狀況 這一種狀況表明咱們選擇要第n+1件商品函數
A = f(n) + w[n+1]
B狀況 咱們不要這一件商品。優化
B = f(n)
因此 f(n+1) = max(A, B)spa
咱們就這樣從第一件一直判斷到第n件就能解決 01揹包問題code
代碼以下:blog
while True: try: N, V = (int(i) for i in input().split()) #這個是用來存商品體積的 ls_v = [0] #這個是用來存商品價值的 ls_w = [0] #咱們創建一個 寬度是 揹包容量加一高度是商品數量加一的列表 f = [[0 for i in range(V+1)] for i in range(N+1)] for i in range(N): v, w = (int(i) for i in input().split()) ls_v.append(v) ls_w.append(w) #這個是咱們遍歷全部商品 for i in range(N+1): #這個是咱們從體積爲零一直增大到體積爲V for j in range(V+1): #若是這個商品比咱們的揹包容量還大確定要捨棄掉所以它的最優解確定和它上一個解同樣 if ls_v[i] > j: f[i][j] = f[i-1][j] else: #這兩個分別表明咱們取這一件商品和不取這一件商品 A = f[i-1][j] #若是取這一件商品那麼揹包確定要被佔據必定空間,而後價值也會增長這件商品的價值 B = f[i-1][j-ls_v[i]] + ls_w[i] f[i][j] = max(A, B) print(f[-1][-1]) except: break
這個我已經運行過確定能夠用。遞歸
而後咱們能夠對它進行優化,時間複雜度降不了了,可是空間複雜度能夠減小。ip
優化代碼以下:input
while True: try: N, V = (int(i) for i in input().split()) f = [0 for i in range(V+1)] def ZeroOnePack(cost, weight, n): for i in range(n, cost-1, -1): f[i] = max(f[i], f[i-cost]+weight) for i in range(N): v, w = (int(i) for i in input().split()) ZeroOnePack(v, w, V) print(f[-1]) except: break
接着是徹底揹包問題:
徹底揹包問題裏 商品就不是每一個只能選一個了,他假設每種商品都有無限多個,最後也是如何選取才能使得價值最大。
while True: try: N, V = (int(i) for i in input().split()) s = [0 for i in range(V+1)] ls_v = [0] ls_w = [0] for i in range(N): v, w = (int(i) for i in input().split()) ls_v.append(v) ls_w.append(w) for i in range(N+1): for j in range(V+1): if ls_v[i] <= j: s[j] = max(s[j], s[j-ls_v[i]]+ls_w[i]) print(s[-1]) except: break
或者寫成函數方程:
while True: try: N, V = (int(i) for i in input().split()) f = [0 for i in range(V+1)] def CompletePack(cost, weight, n): for i in range(cost, n+1): f[i] = max(f[i], f[i-cost]+weight) for i in range(N): v, w = (int(i) for i in input().split()) CompletePack(v, w, V) print(f[-1]) except: break
最後是多重揹包問題:
多重揹包問題就是商品都有必定數量,一樣也是如何選取可以使得所選的組合價值最大。
這裏有兩種思路一種就是轉換成01揹包問題,好比一種商品 體積是 3 價值是 4 數量是 3就能轉化成 三個體積是3價值是4的商品。
代碼以下:
while True: try:
#N是有多少種商品,V是揹包的體積 N,V = (int(i) for i in input().split()) ls_v = [0] ls_w = [0] S = [0 for i in range(V+1)] for i in range(N): v, w, s = (int(i) for i in input().split())
#咱們每次獲得一種商品商品總數就加上該種商品的數量 N += s-1 ls_v += [v]*s ls_w += [w]*s for i in range(1, N+1): for j in range(V, 0, -1): if ls_v[i] <= j: S[j] = max(S[j], S[j-ls_v[i]]+ls_w[i]) print(S[-1]) except: break
還有一種是使用一種是分解成01揹包問題和無限揹包問題while True try:
N,V = (int(i) for i in input().split()) f = [0 for i in range(V+1)] def ZeroOnePack(cost, weight, n): for i in range(n, cost-1, -1): f[i] = max(f[i], f[i-cost]+weight) def CompletePack(cost, weight, n): for i in range(cost, n+1): f[i] = max(f[i], f[i-cost]+weight) def MultiplePack(cost, weight, amount, n):
‘’‘
這裏當數量很大都超過揹包容量和無限次也就沒有區別了,反正揹包又不能全裝走,好比揹包容量爲5商品體積是2
可是有三件很明顯揹包裝不完
’‘’ if cost * amount > n: CompletePack(cost, weight, n) else: #這裏只是爲了把商品數量拆開而已,你徹底能夠把商品拆成一件一件的答案和咱們拆成2的k次方是同樣的 k = 1 while k < amount: ZeroOnePack(k*cost, k*weight, n) amount -= k k *= 2 ZeroOnePack(amount*cost, amount*weight, n) for i in range(N): v, w, s = (int(i) for i in input().split()) #你也能夠不判斷直接調用MultiplePack結果亦同樣只不過程序多走兩部而已。 if s == 1: ZeroOnePack(v, w, V) else: MultiplePack(v,w, s, V) print(f[-1]) except: break
再就是有的會把它全部組合一塊兒,好比有的商品能夠取無限次有的有限次有的只能一次,作法和咱們上面寫的代碼徹底同樣沒有區別,無非多了個判斷咱們調用哪個函數。
二維揹包問題
二維揹包問題就是揹包不但有體積限制還有重量限制,其實和一維揹包問題差不太多無非在創建元組時從原先的一維數組變成二維數組,所用的遞歸公式都差很少。f[v][m] = max(f[v][m], f[v-cost][m-mass] + worth)
while True: try: N, V, M = (int(i) for i in input().split()) f = [[0 for i in range(M+1)]for j in range(V+1)] def ZeroOnePack(cost, mass, worth, n, m): for i in range(n, cost-1, -1): for j in range(m, mass-1, -1): f[i][j] = max(f[i][j], f[i-cost][j-mass] + worth) for i in range(N): v, m, w = (int(i) for i in input().split()) ZeroOnePack(v, m, w, V, M) print(f[-1][-1]) except: break