揹包問題總結一

2021-06-22 22:43:30 字數 3665 閱讀 5282

今天做數論的題目時,遇到一道多重揹包的問題。好久沒做過揹包了,一時有點迷糊,當時理解的也不是很透徹,果斷把揹包九講重新看了一遍。這裡做下總結,加深自己的理解。

揹包問題求的是在花費一定代價(物品的重量或體積)下,乙個揹包裝入物品後所獲得的最大價值。總的包括三種基本的揹包:01揹包,完全揹包,多重揹包。還有由這三種揹包延伸出來的問題:混合揹包,二維費用的揹包,分組揹包,揹包問題問法的變化等。

01揹包是最基本的揹包,有n種物品,第i件物品的花費是c[i],價值是w[i],每種物品只有一件,求將哪些物品裝入揹包獲得的價值最大。

完全揹包,有n種物品,第i件物品的花費是c[i],價值是w[i],每種物品有無限件,求將哪些物品裝入揹包使這些物品的費用不超過揹包容量,且總價值最大。

多重揹包,有n種物品,第i件物品的花費是c[i],價值是w[i],每種物品有有限件為n[i],求將哪些物品裝入揹包使這些物品的費用不超過揹包容量,且總價值最大。

可見,三種揹包的不同之處是物品的數目不一樣。其實完全揹包和多重揹包都可以轉化為01揹包求解。

01揹包

因為每種物品只有一件,有選和不選兩種可能。設f[i][v]表示前i種物品恰好放入容量為v的揹包的最大價值。那麼可以得到狀態轉移方程f[i][v] = max(f[i-1][v], f[i-1][v-c[i]]+w[i]),即第i種物品不放為f[i-1][v],放為f[i-1][v-c[i]]+w[i],取較大值。其時間複雜度為o(nv)。

其實我們可以用乙個一維陣列表示上述狀態的轉移f[v],它與f[i][v]的意義相同。我們可以得到01揹包如下:

void zeroonepack()

}

外迴圈很容易理解,迴圈n次代表n種物品,內迴圈是揹包容量,f[v]對應f[i-1][v],f[v-c[i]]+w[i]對應f[i-1][v-c[i]]+w[i]。但注意是逆序。因為f[v]是從上乙個狀態推出來的,上乙個狀態是f[i-1][v]或f[i-1][v-c[i]]+w[i],即還沒有放當前物品。如果是按順序的話,意味著f[i][v]是由f[i][v-c[i]]推出來,顯然與01揹包每件物品只有一件相違背。

這個圖能夠很好的解釋為什麼是逆序,第1列表示的是三種物品,第一行表示的是揹包的容量。自己動手模擬一下就能明白。

初始化問題:有的題目要求恰好裝滿揹包,而有的沒有要求恰好裝滿,它們在初始化上有細微差別。

如果要求恰好裝滿揹包,那麼f[0]初始為0,f[1...v]初始為-inf(如果求最大價值),最小價值初始為-inf,初始化就是在沒有放任何物品時揹包的合法狀態,因為只有揹包容量為0的時候,恰好有價值為0的nothing"恰好裝滿",它屬於合法狀態,其餘均不是。

如果沒有要求必須裝滿,f[0...v]初始化為0,因為任何容量的揹包都有乙個合法狀態,就是不放入物品。

這裡的初始化也適用於以下的揹包問題。

完全揹包

與01揹包不同的是這裡的每種物品都有無限件,每種物品就不是放與不放的問題了,而是放0個,1個.....v/c[i]個的問題。子狀態f[i][v]定義為前i種物品恰好裝入容量為v的揹包的最大價值。那麼狀態轉移方程為

f[i][v] = max。

它的時間複雜度不是o(nv),而是o(v*∑(v/c[i]) )。

完全揹包可以轉化為01揹包求解,這裡有乙個o(nv)的演算法:

void completepack()

}

可以發現,與01揹包只是內迴圈的順序不同。為什麼這裡是順序呢?想一想01揹包之所以逆序是因為推f[v]時必須是上乙個狀態,即沒放第i種物品的狀態,它保證了每種物品要麼選要麼不選。而這裡每種物品有無限件,當我們加入當前第i種物品進揹包的時候,可能正需要已經放入第i種物品的這樣乙個狀態f[i][v-c[i]]。所以這裡是順序。多重揹包

多重揹包中的每種物品的數目有一定的界限n[i]。每種物品可以放0個,1個......n[i]個。與完全揹包類似,定義子結構f[i][v]表示前i種物品恰好裝入揹包容量是v的最大價值。那麼它的狀態轉移方程為:

f[i][v] = max。

複雜度為o(v*∑n[i])。

轉化為01揹包求解,就是將第i種物品分成n[i]件01揹包中的物品。得到了物品數是∑n[i]件的01揹包。像這樣:

void multiplepack()

}}

還有一種複雜度為o(v*∑(log n[i]))的演算法,利用的是二進位制的思想。就是將第i種物品分成若干件物品,其中每件物品都有乙個係數,這件物品的費用和價值都是原來的費用和價值乘以這個係數。這些係數分別是1,2,4...2^(k-1),n[i]-2^(k)+1,其中k是滿足n[i]-2^k+1>0的最大整數。例如原來n[i] = 13,那麼該種物品可以拆分成4種物品,其係數分別是1,2,4,6。而且可以證明小於等於n[i]的任何數目的物品都可以由拆分後物品的和組成。這樣就減低了複雜度。具體**為:

void zeroonepack(int cost, int weight)

void completepack(int cost, int weight)

void multiplepack()

else

zeroonepack(amount*c[i],amount*w[i]);

} }}

多重揹包問題中還有一類,給出每種物品的價值和數目,問這些物品的組合能否到達某個價值。即判斷是否可達的問題。解決這個問題,經常用乙個陣列use[i]記錄i種物品被用的次數。具體見例題判斷是否可達的問題

揹包問題 01揹包總結

寫這篇部落格的原因是因為自己初學揹包的時候覺得好玄學。只是知道怎麼寫,但是具體是為什麼覺得很玄妙。在此其實希望和我一樣的小白萌新早點明白其中的原理,其實原理很簡單,只要懂了這個圖,我想01揹包就不成問題了。首先要明確這張表是至底向上,從左到右生成的。關於01揹包的題目暫時整理了一點。1.簡單01揹包...

揹包問題總結

標籤 acm dp 揹包 n 物品,乙個揹包,每個物品價值wi 體積vi 揹包容量 c 求最大價值 對於物品 i可選可不選 fi j fi 1 j vi j 0 fi j max c j vi 給定 n 種物品和乙個揹包。第 i種物品的價值是 wi 其體積為vi 揹包的容量為 c 同一種物品的數量無...

揹包問題總結

揹包問題主要是分為三種 0 1揹包,完全揹包,多重揹包 1 0 1揹包 定義 何謂0 1揹包,可以這樣想,那裡有一堆值錢的東西,每一樣東西只有一件,他們的價值和體積都不一樣,現在要你從這n件裡面挑選一些放到乙個容量一定的揹包裡面,使得你的揹包裡的東西總價值最大。對於這些東西的每一件,你可以選擇放進你...