暴力做法
// 动态规划的具体含义 a[N][N] 当含有N件物品同时体积总容量为N的 价值为多少
import java.util.*;
public class Main{
public static void main(String[] args){
int n,m;
int N = 1010;
int[] v = new int[N];
int[] w = new int[N];
int[][] f = new int[N][N];
Scanner scan = new Scanner(System.in);
n = scan.nextInt();
m = scan.nextInt();
for(int i=1;i<=n;i++){
v[i] = scan.nextInt();
w[i] = scan.nextInt();
}
for(int i=1;i<=n;i++){
for(int j=0;j<=m;j++){
// 不拿第i个物品的情况
f[i][j] = f[i-1][j];
// 拿第i个物品的情况 但是前提需要满足当前的容量j要大于要取的物品的重量
if(j >= v[i])
f[i][j] = Math.max(f[i][j],f[i-1][j-v[i]]+w[i]);
}
}
int res = 0;
for(int i=1;i<=m;i++){
res = Math.max(res,f[n][i]);
}
System.out.println(res);
}
}
优化版本
import java.util.*;
public class Main{
public static void main(String[] args){
int n,m;
int N = 1010;
int[] v = new int[N];
int[] w = new int[N];
int[] f = new int[N];
Scanner scan = new Scanner(System.in);
n = scan.nextInt();
m = scan.nextInt();
for(int i=1;i<=n;i++){
v[i] = scan.nextInt();
w[i] = scan.nextInt();
}
for(int i=1;i<=n;i++){
for(int j=m;j>=v[i];j--){
f[j] = Math.max(f[j],f[j-v[i]]+w[i]);
}
}
int res = 0;
for(int i=1;i<=m;i++){
res = Math.max(res,f[i]);
}
System.out.println(res);
}
}
为何能进行这样的优化?
由原来的状态转移方程:
f[i][j] = f[i-1][j] // 在不取i的情况下 转移到上一个状态
// ……两重循环……
f[i][j] = Math.max(f[i][j],f[i-v[i]] + w[i]); // 取得i的情况下 根刚才的不取情况中选择最大值
所以,对于总容量为j的情况下,f[i][j]的状态实际是由上一层的i-1状态更新过来。
为何按照原来的正序就不能达到这样的效果?
当从小到大正序更新的时候,不妨进行举例:
// 取i=10 j=15
f[15] = Math.max(f[15],f[15-v[10]]+w[10]);
而在这里面,v[10]一定是一个非负数,15-v[10]严格小于等于15,因此在这里计算状态转移的时候,是由第i层转移,而不是朴素算法想要达到的从i-1层开始转移。所以正序是不行的。
为何逆序就可以达到这样的效果?
同等上一个例子,15-v[10]严格小于等于15,由于是从大向小迭代,在第i层更小的状态还没有计算,所以只能找到之前i-1层的状态,实现了朴素算法要达到的效果。done