思路:要解决的子问题不单单是数量的变化,判断的条件也会变化,选择同时记住子问题和变化的条件,存下全部变化条件下子问题的最优结果,做为父问题的解答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很小,就是多项式运行时间,这种称为伪多项式运行时间。