F(n,C)考慮將n個物品放入揹包爲C 的揹包,使得價值最大。html
狀態轉移方程:F(i,c) = max(F(i-1 , c) , v(i)+ F(i-1, c- w(i) )數組
根據狀態轉移方程,第i行元素計算只依賴與i-1行元素。理論上咱們只須要保持兩行元素。優化
如上圖,咱們初始化後第一行存放0行元素,第二行存放1行元素。而第二行元素能夠之間使用再也不使用的0行元素。spa
發現規律:第一行一直爲偶數行,第二行一直爲奇數行,因此咱們能夠使用一個行數爲2的二維數組來儲存。code
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)htm
使用上一篇的例子,將其優化爲兩行。blog
發現dp[i][j] 只須要上一行的左邊與上方的元素,而右邊的元素並不須要。故嘗試以下優化get
咱們僅僅使用一行元素記錄。class
更新位置5的元素,只須要位置3的元素以及本身(即上一種狀況的上一行元素)便可。im
同理,更新位置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]; } }