有n件物品和乙個容量為v的揹包。第i件物品的費用是v[i],價值是w[i]。求解將哪些物品裝入揹包可使價值總和最大。
要麼拿,要麼不拿
關鍵就在於找到它的最優子問題,物品為n個,體積為v,我們需要取二維狀態的dp比如我們想要知道前5個物品放入體積為9的揹包中最大價值是多少,物品id為0-4
將前i個物品放入體積為j的揹包中可以獲得的最大價值
->dp[i][j]
只有單件物品就只需要考慮放或者不放,如果放入,體積就需要減去v[i],價值就加上w[i]
也就是求dp[4][9],
需要知道dp[3][j]
,0要知道dp[3][j]
,我們就要知道dp[2][j]
,再對物品3進行選取,根據01揹包狀態轉移方程計算dp[3][j]
最大價值;要知道
dp[2][j]
,我們就要知道dp[1][j]
,再對物品3進行選取,根據01揹包狀態轉移方程計算dp[2][j]
最大價值;要知道
dp[1][j]
,我們就要知道dp[0][j]
,再對物品3進行選取,根據01揹包狀態轉移方程計算dp[0][j]
最大價值;把
dp[i][0]
初始化為0(0<=i第一次優化:二維陣列優化為一維陣列我們可以從**發現,當前行的資料只與上一行的資料有關,所以我們只要每次迴圈後確保陣列儲存了上一次計算的結果public int napzack01_first(int w,int v,int v,int n)
問題以及解決:
我們從當前迴圈來看,計算體積為
5
的dp值最多隻需要0-4
的上一次計算的結果,如果順序從小到大更新的話,我們計算5
時,此時之前的0-4
的值都被更新了,不是上一次計算的結果(而是當前計算的結果),而後面的需要上一次前面的資料;所以我們不能從頭開始,而應該從最後開始更新,從後往前,這樣可以保證優先更新體積大的值而讓體積小的值保留上一次就算的結果。
//1維01揹包
public int napzack01_second(int w,int v,int v,int n)
全部放滿01揹包:
我們之前討論了一種是不要求全部放滿的01揹包,我們再看如果要求全部放滿會有什麼不同如果我們把物品表換成這樣:如果我們想要全部放滿,就拿不到物品4,即使它價值50,但是我們想要的是要把揹包裝滿,這就涉及到初始化時的問題
我們需要為每一次迴圈放入物品到j的揹包中設定乙個能否放滿的標誌,每次判斷這個標誌來檢查當前物品放入能否使得揹包裝滿我們只需要在初始化時把一維陣列的
1-v
初始化為-1
,表示當前0個物品放入揹包,不能裝滿這些體積的揹包,把陣列dp[0]
正常設定為0,表示體積為0的揹包可以被0個物品裝滿;然後我們在計算陣列值時先判斷dp[j-v[i]]
是否為-1,為-1說明當前物品放入無法裝滿揹包,則不進行修改陣列的值;只有不為-1才能繼續放入,說明當前物品放入可以放滿體積為j
的揹包
//全部放滿01揹包
public int napzack01_fourth(int w,int v,int v,int n)
有n件物品(每個物品都有無限個)和乙個容量為v的揹包。第i件物品的費用是v[i],價值是w[i]。求解將哪些物品(每個物品都可以裝多個)裝入揹包可使價值總和最大。我們每種物品最多有選取v/v[i]
個,我們可以再多一次迴圈,計算選取0-v/v[i]
個的最大價值
時間複雜度:每種物品有v/v[i]個,共需要求解nv中狀態,時間為o(nvς(v/v[i]))狀態轉移方程:空間複雜度:o(n)
dp[j] = max
code
//完全揹包
,完全揹包因為需要累計多個同一物品的值,前一次計算可能是1個、2個等等,下一次j變化了以後,計算的可能是3個或者更多,所以我們需要儲存實時計算出來的多個同一物品的最大價值,我們選取從前往後的順序,這樣每次前面計算的我們都可以在j增大以後累加獲得更多個同一物品的最大價值(根據狀態轉移方程可知,我們計算乙個位置的最大價值只需要當前位置的上一次計算的值和當前次迴圈內更前面的值)//狀態轉移方程 dp[j] = dp[j-k*v[i]]+k*w[i]
public int napzack_complete(int w,int v,int n,int v){
int dp = new int [v+1];
for(int i=0;i我們記得在優化01揹包時,我們為了獲取到上一次計算的值,我們選擇從後往前計算,但是完全揹包正好相反,這才是它此昂要的
例如:在我們計算第2個物品dp[5]的時候,物品2的體積為2,價值為5,我們需要上一次計算也就是第乙個物品的dp[5]的值,還需要dp[5-2]=dp[3]的值,dp[3]我們在本次迴圈內計算dp[5]之前就已經算過了,dp[3]可能選了乙個物品2,也可能沒有選,我們計算dp[5]就根據這個dp[3]的大小在進行選取,就可以進行多次選取。
根本上就是把一類物品轉化為多個一種物品
我們不需要體積從0開始計算。而只需要在每個物品的迴圈內從當前物品的最小個數1開始,也就是引數依然使用v[i]
(不需要0個是因為初始化的時候已經把體積為0的dp值設定為0了)
code
//把完全揹包優化為01揹包
public int napzack_comlete01(int w,int v,int n,int v){
int dp = new int[v+1];
for(int i=0;i
本篇文章由一文多發平台artipub自動發布
揹包問題 01揹包問題
n個物品,總體積是v,每個物品的體積的vi,每個物品的最大價值是wi,在不超過v的體積下求最大價值 eg揹包容積為 5 物品數量為 4 物品的體積分別為 物品的價值分別為 思路定義乙個二位陣列int f new int n 1 v 1 f i j 就表示在1 i個物品中選取體積小於v的情況的最大價值...
揹包問題 01揹包
有n件物品和乙個容量為v的揹包。第i件物品的重量是c i 價值是w i 求解將哪些物品裝入揹包可使價值總和最大。01揹包中的 01 就是一種物品只有1件,你可以選擇放進去揹包即1,也可以選擇不放入揹包中即0。include include using namespace std const int ...
揹包問題(01揹包)
1085 揹包問題 在n件物品取出若干件放在容量為w的揹包裡,每件物品的體積為w1,w2 wn wi為整數 與之相對應的價值為p1,p2 pn pi為整數 求揹包能夠容納的最大價值。input 第1行,2個整數,n和w中間用空格隔開。n為物品的數量,w為揹包的容量。1 n 100,1 w 10000...