揹包問題是動態規劃最經典的問題之一,這篇部落格會初步探索揹包問題,在後續系列會繼續深入。
有n個物品,價值和重量分別為vi和wi,揹包承重w,求裝入揹包的最大價值。
例子:n=4
w=v=
w=5輸出
v=7(選擇第0,1,3件物品或者第2,3件物品)
情況1在揹包還放得下這件物品時,選與不選都試一下,選二者的較大值
情況2在揹包放不下這件物品的時候,直接跳過這件物品
情況3沒有物品可選
例如上例
物品1:我們先看第乙個物品 w=2,v=2,w可用為5,此時是情況1,
也就是說此時要選擇max(放第一件物品,不放第一件物品)
物品2:再看第二個物品,因為物品有兩種情況,放第一件物品與不放,所以第二件物品要分情況討論。
當不放第一件物品時,第二個物品 w=1 , v=2,w可用為5,此時是情況1,
也就是說此時要選擇max(放第二件物品,不放第二件物品)
當放第一件物品時,第二個物品 w=1,v=2,w可用為5-2=3,此時是情況1,
也就是說此時要選擇max(放第二件物品,不放第二件物品)
物品3:以此類推,類似像樹形展開。如下圖所示:
紅色字型是遞迴出口向上一層一層返回。
基於以上分析,不難想到利用遞迴來解決這個問題。既然利用遞迴,那麼就要想好遞迴函式是否需要返回值,引數型別,遞迴條件,遞迴出口。
返回值:明顯要返回int。
引數型別:我們需要從第乙個物品搜尋到最後一和物品,所以引數肯定要乙個陣列的下標i(從0開始)表示當前在選擇的物品,我們還需要知道當前揹包還剩餘的體積是多少,所以需要乙個引數j來表示它,很明顯i的初始呼叫值為0,j的初始呼叫值為w.
遞迴條件:
情況1:在揹包還放得下這件物品時,選與不選都試一下,選二者的較大值
情況2:在揹包放不下這件物品的時候,直接跳過這件物品
遞迴出口:沒有物品可選
分析好這些所有的必備條件後,**就很簡單了
普通遞迴**
public
intrec
(int i,
int j)
else
if(j
)else
return res;
}
用乙個記憶陣列dp儲存上面遞迴生成的資料,防止重複遞迴,避免浪費。
int dp[
]=newint
[n+1
][w+1]
;public
intrec1
(int i,
int j)
else
if(j
)else
return dp[i]
[j]=res;
}
public
intrec2
(int i,
int j,
int sum)
else
if(j
)else
return res;
}
從上面的分析很容易得出動態規劃方程
沒有物品選
dp[n][j]=0
選不了這個物品
dp[i][j]=dp[i+1][j]
選與不選取較大者
dp[i][j]=math.max(dp[i+1][j],dp[i+1][j-w[i]]+v[i])`
dp[i][j]表示從第i個物品開始選擇總重小於等於j的部分
int dp[
]=newint
[n+1
][w+1]
;public
intdp()
else}}
return dp[0]
[w];
}
上面動態規劃是逆向的,要想正向的話,必須重新設計動態規劃方程。
dp[i+1][j]表示從前i個物品選擇總重小於等於j的物品
dp[0][j]=0
dp[i+1][j]=dp[i][j] (jint dp[
]=newint
[n+1
][w+1]
;public
intdp1()
else}}
return dp[n]
[w];
}
動態規劃之01揹包問題
首先是問題描述 給定n種物品和一揹包,物品i的重量是wi,其價值是pi,揹包的容量是m,問如何選擇裝入揹包中的物品總價值最大?可以這樣理解 揹包的揹負有上限,因此在這個上限內盡可能多的裝東西,並且價值越多越好。在這裡我之想討論動態規劃解決這個問題的詳細過程。動態規劃是用空間換時間的一種方法的抽象。其...
動態規劃之0 1揹包問題
問題描述 現有n件物品和乙個容量為c的揹包。第i件物品的重量是重量為w i 價值是v i 已知對於一件物品必須選擇取 用1表示 或者不取 用0表示 且每件物品只能被取一次 這就是 0 1 的含義 求放置哪些物品進揹包,可使這些物品的重量總和不超過揹包容量,且價值總和最大。求解思路 0 1揹包問題的遞...
動態規劃之0 1揹包問題
問題描述 0 1揹包問題是應用動態規劃設計求解的典型例題 已知n種物品和乙個可容納c重量的揹包,物品i的重量為w i 產生的效益為p i 在裝包時物品i可以裝入,也可以不裝,但不可拆開裝。問如何裝包,所得裝包總效益最大。演算法分析 最優子結構特性 0 1揹包的最優解具有最優子結構特性。與一般揹包問題...