输入
4 5
1 2
2 4
3 4
4 5
题目:小明有容量m的袋子,有n个物品 物品有价值和体积,问最多能装多少价值的物品。
前两个数为n,m (n为n个物品,m代表有m容量的袋子)
01背包
static int[] v;
static int[] w;
static int n,W;
public static int dp01(int []v,int[] w) {
int dp[][] = new int[n+2][n+2];
for(int i = 1;i <= n;i++){
for(int j = 0;j <= W;j++){
if(j >= v[i]){
dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-v[i]] + w[i]);
} else {
dp[i][j] = dp[i-1][j];
}
}
}
int rs = 0;
for(int i = 0;i <= W;i++){
rs = Math.max(rs,dp[n][i]);
}
return rs;
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
while(sc.hasNextInt()){
n = sc.nextInt();
W = sc.nextInt();
v = new int[n+1];
w = new int[n+1];
for(int i = 1;i <= n;i++){
v[i] = sc.nextInt();
w[i] = sc.nextInt();
}
System.out.println(dp01(v,w));
}
}
滚动数组优化01背包:
public static int dp01(int []v,int[] w) {
int dp[] = new int[n+2];
for(int i = 1;i <= n;i++){
for(int j = W;j >= 0;j--){
if(j >= v[i]){
dp[j] = Math.max(dp[j], dp[j-v[i]] + w[i]);
}
}
}
int rs = 0;
for(int i = 0;i <= n;i++){
rs = Math.max(rs,dp[i]);
}
return rs;
}
现在我们用正序遍历一遍
当i = 1时
f[0] = 0 ,f[1] = 0,f[2] = 0,f[3] =0 (显然当前容积小于该物品的体积,自然就放不进去,统统初始化为0)
f[4] = max( f[4],f[0]+3) 即f[4] = max(0,0+3) = 3;
f[5] = max( f[5],f[1]+3) 即f[5] = max(0,0+3) = 3;
f[6] = max( f[6],f[2]+3) 即f[6] = max(0,0+3) = 3;
f[7] = max( f[7],f[3]+3) 即f[7] = max(0,0+3) = 3;
f[8] = max( f[8],f[4]+3) 即f[8] = max(0,3+3) = 6;
大家快看!!!!!!!!!!!!
有奇怪的事发生了,人群之中竟然钻出了两个.....两个f[4]!!!
那么问题来了,还记得01背包的性质么?这个序号为1的物品竟然用了两次!!!
[8] = max(f[8],f[4]+3)即f[8] = max(0,0+3) = 3;
f[7] = max(f[7],f[3]+3)即f[7] = max(0,0+3) = 3;
f[6] = max(f[6],f[2]+3)即f[8] = max(0,0+3) = 3;
f[5] = max(f[5],f[1]+3)即f[5] = max(0,0+3) = 3;
f[4] = max(f[4],f[0]+3)即f[4] = max(0,0+3) = 3;
f[3] = 0,f[2] = 0,f[1] = 0,f[0] = 0
不知道大家发现没有,逆序遍历在向前滚动的时候并没有对更小体积的清况进行更新,而正序时却对同一件物品进行了多次操作。
————————————————
参考:https://blog.youkuaiyun.com/qq_40828060/article/details/78422412