#動態規劃 0-1揹包問題思路概述

 

01揹包問題是動態規劃中的經典問題。

本篇文章主題:分析與優化最基本的01揹包問題,對此類問題解題有一個基本的解題模板。

 

問題概述:

有一個揹包,他的容量爲C(Capacity)。如今有n種不一樣的物品編號分別爲0、1....n-1。其中每一件物品的重量爲w(i),價值爲v(i)。問能夠向這個揹包中放入哪些物品,使得在不超過揹包容量的基礎上,揹包內物品價值最大。數組

 

 

思路:

1.暴力法。

每一件物品均可以放進揹包,也能夠不放進揹包。找出全部可能組合一共2^n種組合數據結構

時間複雜度:O((2^n)*n)函數

 

2.動態規劃法。

咱們首先使用遞歸函數自上而下進行思考。優化

明確兩點:spa

第1、遞歸函數的定義3d

第2、數據結構code

 

函數定義:

F(n,C)遞歸函數定義:將n個物品放入容量爲C的揹包,使得價值最大。視頻

這裏要注意一下,第二個參數必定是剩餘容量。咱們經過使用剩餘容量來控制價值。blog

F(i,c) = F(i-1,c)遞歸

       = v(i) + F(i-1 , c-w(i))

狀態轉移方程:

F(i,c) = max( F(i-1 , c) , v(i) + F(i-1 , c-w(i) ) )

即,當前價值的最大值爲,不放入第i個物品(對應剩餘容量爲c)和放入第i個物品(對應剩餘容量爲C-w(i))兩種狀況的最大值。

 

數據結構:

借某盜版視頻中的一個例子:

 

 

 咱們這裏選擇一個二維數組,來迭代記錄處理的結果。

這個二維數組dp[n][C] 其中n爲物品數量,C爲最大容量。

儲存的值dp[i][j]含義爲:考慮放入0~i 這些物品, 揹包容量爲j

咱們考慮放入第一個物品。

因爲第一個物品,編號爲0,重量爲1,價值爲2。

對於容量爲0的揹包,放不下該物品,因此該揹包價值爲0.

其他容量1~5,都可放下該物品。因此只考慮物品0,不一樣揹包大小對應的最大可能價值如圖。

第一行處理爲初始化,從第二行開始進行迭代。

 

 第二行開始,就須要單獨處理。

考慮dp[1][0],揹包容量爲0,理所應當爲0

考慮dp[1][1],此處咱們依舊沒法放入物品1,因此咱們使用上一層的結果,即0~0物品在容量爲1揹包狀況的最大價值。

考慮dp[1][2],此處咱們終於能夠放下物品1了,因此咱們考慮若是要放下物品1,剩餘揹包最大的可能價值,即dp[0][0]

咱們對比上一層的狀況,以及掏空揹包放入物品2的狀況。發現最大值爲後者,因此dp[1][2]爲10

 

 同上,咱們掏出能夠放下物品1的空間,考慮此時最大價值,即dp[0][1]。對比他和上一層dp[0][3]的大小,發現前者大。

故此時dp[1][3]爲dp[0][1]+v[1] = 16.

 

以此類推,咱們每次清空對應物品大小的揹包,而後放入對應物品,對比不放入物品的上一行。求出最大值

依次填入dp[][]得出最終的二維數組。

 

代碼以下

 

class Knapasack01{
    public :
        int knapsack01(int[] w,int[] v,int C){
//w爲0-~n-1物品對應價值
//v爲0~n-1物品對應重量。
//C爲揹包容量
            
            int n = w.length();
            if(n == 0)
                return 0;
   //動態規劃記憶數組。         
            int[][] dp = new int[n][C];
//初始化第一行。
            for(int j=0 ; i<= C ; j++)
                dp[0][j] = (j>=w[0]?v[0]:0);
            
            for(int i=1 ; i<n ; i++)
                for(int j=0 ; j<C ; j++){
                    dp[i][j] = dp[i-1][j];
                    if(j>=w[i])
                        memo[i][j] = (int)Math.max(dp[i][j] , v[i]+dp[i][j-w[i]]);
                }
          return dp[n-1][C];  
        }   
}
相關文章
相關標籤/搜索