假設有abcde5個物品,重量爲w1...,價值爲v1...,揹包的承重量爲c,怎麼放的價值更高數組
1、0/1揹包問題優化
5中物品只有一件,動態規劃的子問題是前i個物品放在承重量爲j的揹包中,狀態變量:dp[i][j]spa
遍歷時i在外層,j在內層,也就是每次循環先求出前i-1個物品在不一樣載重量的狀況下的自大價值code
而後增長一個物品,也就是前i個物品。blog
而在求前i個物品的最大價值時根據前i-1的結果:class
1.當前載重量<新增的第i件物品的重量w[i],也就是裝不下變量
dp[i][j] = dp[i-1][j]循環
2.裝得下遍歷
dp[i][j] = max(dp[i-1][j-w[i]]+v[i],dp[i-1][j]):比較裝和不裝,其中若是裝當前物品,那麼重量佔了w[i],前邊i-1件物品只能使用j-w[i]的重量di
到這裏時間複雜度無法優化,可是還能優化空間複雜度
咱們能夠觀察到,這裏的i只是記錄進行到前多少件物品了,其實咱們不須要前幾件的結果,咱們須要的是最後的結果,因此咱們沒有必要記錄
i的信息。能夠用一個一維數組dp[j]只記錄當前信息i件物品下,不一樣載重量的價值。而後每次都更新。更新到最後就是想要的
這裏雖然不記錄i的信息,可是仍是要保留循環,表明這是前i件的狀況,i不一樣的狀況下,dp[j]是不一樣的。
注意這裏須要倒着遍歷,由於dp[j]會不斷更新,前邊更新的結果不能影響後邊
若是從前邊開始,前邊的dp[j]就會更新爲i的狀態,i-1的狀態就消失了,可是後邊須要這些
若是從後邊開始,前邊的用不到後邊的結果
public void p01(int[] w,int[] v,int c){ int[] dp = new int[c+1]; for (int i = 0; i < w.length; i++) { // 注意這裏須要倒着遍歷,由於dp[j]會不斷更新,前邊更新的結果不能影響後邊 // 若是從前邊開始,前邊的dp[j]就會更新爲i的狀態,i-1的狀態就消失了,可是後邊須要這些 // 若是從後邊開始,前邊的用不到後邊的結果 for (int j = c; j >=w[i]; j--) { dp[j] = Math.max(dp[j],dp[j-w[i]]+v[i]); } } System.out.println(dp[c]); }
2.徹底揹包問題
物品數量沒有限制
public void pComplete(int[] w,int[] v,int c){ int[] dp = new int[c+1]; for (int i = 0; i < w.length; i++) { //這裏應該從前日後遍歷,01揹包不能從前日後的緣由實際上是若是當前承重量能夠裝下多件第i件物品時 //01問題不能裝多個,因此裝完後要用前一次的狀態比較(前一次確定是沒有裝i的) //可是徹底揹包不一樣,裝完後要用最新的狀態比較,由於還能夠繼續裝i for (int j = w[j]; j <=c; j++) { dp[j] = Math.max(dp[j],dp[j-w[i]]+v[i]); } } System.out.println(dp[c]); }