92 揹包問題

原題網址:https://www.lintcode.com/problem/backpack/descriptionhtml

描述

在n個物品中挑選若干物品裝入揹包,最多能裝多滿?假設揹包的大小爲m,每一個物品的大小爲A[i]面試

你不能夠將物品進行切割。segmentfault

您在真實的面試中是否遇到過這個題?  

樣例

若是有4個物品[2, 3, 5, 7]數組

若是揹包的大小爲11,能夠選擇[2, 3, 5]裝入揹包,最多能夠裝滿10的空間。markdown

若是揹包的大小爲12,能夠選擇[2, 3, 7]裝入揹包,最多能夠裝滿12的空間。app

函數須要返回最多能裝滿的空間大小。函數

挑戰

O(n x m) time and O(m) memory.post

O(n x m) memory is also acceptable if you do not know how to optimize memory.優化

標籤
揹包問題
LintCode 版權全部
動態規劃(DP)

 

思路:url

揹包問題是動態規劃的一種題型,它的特色以下:

1. 用值做爲dp維度
2. dp過程就是填寫矩陣
3. 能夠用滾動數組進行優化  轉自此文

dp【i】【j】表示前 i 個物品放到容量爲 j 的揹包裏可以佔用的最大致積。

狀態轉移方程爲:dp【i】【j】= max(dp【i-1】【j】,dp【i-1】【j-A【i】】+A【i】)。

每一個物品只有兩種狀態,放或者不放。對於容量爲 j 的揹包,放入第 i-1 件物品後佔用的最大致積爲dp【i-1】【j】,如今考慮第 i 件物品。

不放,dp【i】【j】=dp【i-1】【j】;

放,須要從 j 中騰出A【i】的空間,再看剩餘的空間放前 i-1 件物品最大能佔多少空間,即dp【i】【j】=A【i】+ dp【i-1】【j-A【i】】。(注意前提是 j >= A【i】)

最後的dp【i】【j】就是上述兩種狀況的較大值。

 

AC代碼,時間複雜度O(m×n),空間複雜度O(m×n):

class Solution { public: /** * @param m: An integer m denotes the size of a backpack * @param A: Given n items with size A[i] * @return: The maximum size */
    int backPack(int m, vector<int> &A) { // write your code here
    if (A.empty()) { return 0; } int size=A.size(); vector<vector<int>> dp(size,vector<int>(m+1,0)); //初始化第一行,即只有第一個物品時,若揹包容量大於等於A[0],放物品能佔用的最大空間爲A[0];
    for (int j=0;j<=m;j++) { if (j>=A[0]) { dp[0][j]=A[0]; } } //計算dp其餘元素;
    for (int i=1;i<size;i++) { for (int j=0;j<=m;j++) { if (j>=A[i])//能放A[i],計算此時的最大致積,注意是大於等於;
 { dp[i][j]=dp[i-1][j-A[i]]+A[i]; } dp[i][j]=max(dp[i-1][j],dp[i][j]); } } return dp[size-1][m]; } };

 

PS:狀態轉移方程簡而言之就是,揹包容量爲 j 時,能放得下 i 就騰出A【i】的空間,再看剩餘的空間放前 i-1 件物品最大能佔多少空間,兩者之和與不放 i 能佔用的最大致積比,哪一個大就取哪一個;放不下就直接看0~i-1能佔用 j 的最大容量是多少;

再PS:dp數組優化前,j是從前向後遍歷仍是從後向前遍歷都不影響其結果,由於計算當前i是參照i-1時的數據。 

 

利用滾動數組優化空間複雜度:

建立一維動態數組dp,dp【j】仍然表示前 i 個物品放到容量爲 j 的揹包裏可以佔用的最大致積。

狀態轉移方程爲:j從m依次遞減到0,dp【j】= max(dp【j】,dp【j-A【i】】+A【i】)。

推導思路與二維dp相同。只不過代碼實現的時候要注意,列方向須要從後向前計算(防止覆蓋未參加計算的上一行數據),這樣就實現了用當前行不斷代替前一行。

不難理解,i=0時是正常計算的。i≠0時,二維dp【i】【j】= max(dp【i-1】【j】,dp【i-1】【j-A【i】】+A【i】),注意等號右邊的dp數組行下標都是i-1,即前一行的數據。一維dp時,j從後向前遍歷,則參與計算的dp【j】與dp【j-A【i】】都是上一行的值。

 

AC代碼:

class Solution { public: /** * @param m: An integer m denotes the size of a backpack * @param A: Given n items with size A[i] * @return: The maximum size */
    int backPack(int m, vector<int> &A) { // write your code here
    int size=A.size(); vector<int> dp(m+1,0); for (int i=0;i<size;i++) { for (int j=m;j>=0;j--)//從後向前計算,保證了參與運算的是上一行的dp[j]與dp[j-A[i]];
 { if (j>=A[i])//注意是大於等於;
 { dp[j]=max(dp[j],dp[j-A[i]]+A[i]); } } } return dp[m]; } };

 

 

參考:

lintcode backpack 揹包問題  講解清晰易懂

lintcode:揹包問題

【LintCode】Backpack 揹包問題

LintCode揹包問題總結  總結了一系列揹包問題,能夠好好參考。

[LintCode] Backpack I II III IV V VI [揹包六問]

相關文章
相關標籤/搜索