思路:要解決的子問題不單單是數量的變化,判斷的條件也會變化,選擇同時記住子問題和變化的條件,存下全部變化條件下子問題的最優結果,做爲父問題的解答bash
總共n個物件,每一個物件的重量爲,是個Integer,每一個物件價值爲,揹包能裝下的重量爲S,求每次獲取最大價值的裝法。
分析以下:揹包能裝下的重量是有限的,若是物件自己的重量是大於揹包的能裝範圍,價值再大也不能裝,對於剩餘重量小於揹包能裝範圍:spa
選擇的方案總共有兩種,那種方式使得價值最大就選擇對應的裝的方式.net
假設有以下示例:code
總共有3個物件,揹包限量爲5kg。物件分別爲
A價值10元,4kg
B價值4元,2kg
C價值7元,3kg
複製代碼
揹包裏頭剛開始什麼都沒有,也就是剛開始的時候什麼都不拿,揹包中的價值都是0。get
0 | 1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 |
A | ||||||
B | ||||||
C |
橫軸表示揹包能裝的重量,縱軸表示物件,每一個單元格表示對應重量中揹包能裝的最大價值string
假設這個時候只有一個物件A,它的重量是4kg,根據揹包能裝的條件必須是揹包的容量至少是4kg,不然不管價值是多少,容量不夠確定不能裝it
0 | 1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 |
A | 0 | 0 | 0 | 0 | ||
B | ||||||
C |
列爲0表示容量爲0io
此時容量已經到達4了,有兩個選擇table
能夠看到裝A帶來的價值更大class
0 | 1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 |
A | 0 | 0 | 0 | 0 | 10 | |
B | ||||||
C |
當容量到達5時,和4作同樣的考慮,有DP(0,1)+10=0+10>DP(0,5)=0,於是繼續選擇裝A價值更大
0 | 1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 |
A | 0 | 0 | 0 | 0 | 10 | 10 |
B | ||||||
C |
物件A的選擇已經窮盡,此時能夠看作'A已經裝在揹包了'。考慮物件B,它的重量爲2kg
0 | 1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 |
A | 0 | 0 | 0 | 0 | 10 | 10 |
B | 0 | 0 | 4 | 4 | ||
C |
當容量爲4的時候狀況出現了一點變化
能夠看到A,B二者在容量爲4時,選擇只裝A是更優的選擇,一樣的狀況適用於容量5
0 | 1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 |
A | 0 | 0 | 0 | 0 | 10 | 10 |
B | 0 | 0 | 4 | 4 | 10 | 10 |
C |
而後考慮C,此時揹包已經考慮過裝A,B的狀況
0 | 1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 |
A | 0 | 0 | 0 | 0 | 10 | 10 |
B | 0 | 0 | 4 | 4 | 10 | 10 |
C | 0 | 0 | 4 |
當容量爲3時
DP(2,0)表示在容量爲0的狀況下,A+B都考慮是否裝的最優價值
得出只裝C更好
0 | 1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 |
A | 0 | 0 | 0 | 0 | 10 | 10 |
B | 0 | 0 | 4 | 4 | 10 | 10 |
C | 0 | 0 | 4 | 7 |
當容量爲4時
不裝C更好
0 | 1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 |
A | 0 | 0 | 0 | 0 | 10 | 10 |
B | 0 | 0 | 4 | 4 | 10 | 10 |
C | 0 | 0 | 4 | 7 | 10 |
當容量爲5時
裝C更好
0 | 1 | 2 | 3 | 4 | 5 | |
---|---|---|---|---|---|---|
0 | 0 | 0 | 0 | 0 | 0 | 0 |
A | 0 | 0 | 0 | 0 | 10 | 10 |
B | 0 | 0 | 4 | 4 | 10 | 10 |
C | 0 | 0 | 4 | 7 | 10 | 11 |
由此能夠獲得結論,容量爲5,當前條件下最優的價值是11。
代碼以下
public static void main (String[] args) throws Exception{
//code
BufferedReader br=new BufferedReader(new InputStreamReader(System.in));
int round=Integer.parseInt(br.readLine());
for(int r=1;r<=round;r++){
//物件的個數
int N=Integer.parseInt(br.readLine());
//揹包的容量
int W=Integer.parseInt(br.readLine());
String[] vStrs=br.readLine().split(" ");
String[] wtStrs=br.readLine().split(" ");
int[] v=new int[N+1];
int[] wt=new int[N+1];
for(int i=0;i<N;i++){
//物件的價值
v[i]=Integer.parseInt(vStrs[i]);
//物件的重量
wt[i]=Integer.parseInt(wtStrs[i]);
}
int[][] dpV=new int[N+1][W+1];
for(int i=1;i<=N;i++){
for(int j=1;j<=W;j++){
int result=dpV[i-1][j];
if(wt[i-1]<=j){
result=Math.max(v[i-1]+dpV[i-1][j-wt[i-1]],dpV[i-1][j]);
}
dpV[i][j]=result;
}
}
System.out.println(dpV[N][W]);
}
}
複製代碼
總共的耗時時間爲O(NW),與揹包的容量和物件的個數都有關。
僞多項式運行時間
從上面看到揹包問題須要的時間爲O(ns),其中s表示揹包的最大容量,一個物件的最大容許放的大小就是S,存放在電腦上起碼須要 logS 的空間。而總共的個數有 n 個須要處理,因此花銷的空間大小爲 O(nlogS),假設logS=b,即輸入大小爲 O(nb),那麼運行時間爲,也就是隨着輸入的變大,運行時間會變成指數增加,可是若是b很小,就是多項式運行時間,這種稱爲僞多項式運行時間。