#動態規划 0-1背包問題空間復雜度優化


上一個版本的0-1背包代碼的復雜度:時間復雜度O(n*C)空間復雜度O(n*C)

優化思路如下:

0-1背包問題:

F(n,C)考慮將n個物品放入背包為C 的背包,使得價值最大。

狀態轉移方程:F(i,c) = max(F(i-1 , c)  ,   v(i)+ F(i-1, c- w(i)  )

根據狀態轉移方程,第i行元素計算只依賴與i-1行元素。理論上我們只需要保持兩行元素。

 

如上圖,我們初始化后第一行存放0行元素,第二行存放1行元素。而第二行元素可以之間使用不再使用的0行元素。

發現規律:第一行一直為偶數行,第二行一直為奇數行,所以我們可以使用一個行數為2的二維數組來儲存。

代碼如下:

class Knapsack02{
    public int knapsack02(int[] w , int [] v, int C){
        assert(w.length == v.length && C>=0);

        int n = w.length;
        if(n == 0 || C==0)
            return 0;

        int[][] memo = new int[2][C+1];

        //第一行初始化。
        for(int i = 0 ; i<=C ; i++)
            memo[0][i] = (i>=w[0]?v[0]:0);

        for(int i =1 ; i<n ; i++)
            for(int j =0 ; j<=C ; j++){
                memo[i%2][j] = memo[(i-1)%2][j];
                if(j>=w[i])
                    memo[i%2][j] = (int)Math.max(memo[i%2][j] , v[i]+memo[(i-1)%2][j-w[i]]);
            }
            
        return memo[(n-1)%2][C];    
    }

}

空間復雜度:O(2*C)

 

繼續優化:

使用上一篇的例子,將其優化為兩行。

 

發現dp[i][j] 只需要上一行的左邊與上方的元素,而右邊的元素並不需要。故嘗試如下優化

我們僅僅使用一行元素記錄。

更新位置5的元素,只需要位置3的元素以及自己(即上一種情況的上一行元素)即可。

 

 

同理,更新位置4也僅僅需要自己當前元素以及位置2的元素。

 

 優化后數組為此。

我們僅僅需要一行元素,找到其對應的dp[j-v(i)]即可(物理意義為,掏空足夠的空間,放入當前元素,選取不放入當前元素和放入的較大值)。

 

代碼實現如下:

class Knapsack03{
    public int knapsack03(int[] w , int [] v, int C) {
        assert (w.length == v.length && C >= 0);

        int n = w.length;
        if (n == 0 || C == 0)
            return 0;

        int[] memo = new int[C + 1];

        //第一行初始化。
        for (int i = 0; i <= C; i++)
            memo[i] = (i >= w[0] ? v[0] : 0);

        for (int i = 1; i < n; i++)
            for (int j = C; j >= w[i]; j++) {
                memo[j] = (int) Math.max(memo[j], v[i] + memo[j - w[i]]);

           
            }
        return memo[C];
    }
}

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM