二维版:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;public class Main {static int N = 1010;static int[][] dp = new int[N][N]; //dp[i][j] 只选前i件物品,体积 <= j的最优解static int[] w = new int[N]; //存储价值static int[] v = new int[N]; //存储体积static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));public static void main(String[] args) throws IOException{String[] init = in.readLine().split(" ");int n = Integer.parseInt(init[0]);int Vmax = Integer.parseInt(init[1]);for(int i = 1;i <= n;i ++) {init = in.readLine().split(" ");v[i] = Integer.parseInt(init[0]);w[i] = Integer.parseInt(init[1]);}for(int i = 1;i <= n;i ++) {for(int j = 1;j <= Vmax;j ++) {if (v[i] > j) { //当前背包装不下.最优解就是上一层的数据dp[i][j] = dp[i - 1][j];} else {//装得下的话,背包的价值会变成dp[i - 1][j - v[i]] + w[i]// j - v[i] 体积下的最优解 + w[i] 不一定会胜过dp[i - 1][j]dp[i][j] = Math.max(dp[i-1][j], dp[i - 1][j - v[i]] + w[i]);}}}System.out.print(dp[n][Vmax]);in.close();}
}
f[i][j]:只从前i个物品全,总体积<=j的最优解。局部最优=>全局最优
一维版
由模拟二维的过程可知,通过不断覆盖前一维的状态,只一维数组也能实现
并且,并不是一维里的所有数据都需要更新,所以可以更新二维起始下标
二维更改一维需要满足条件,在决策dp[i][j]时,要能够知道dp[i - 1][j - v[i]]的状态
要用的是一行的数据,不能用当前行的数据
如表格中在决策第二件物品(v=2)时,dp[2]计算时,会把2更新成4,dp[4]计算时,需要用到上一次的2,而不是被更新过的4。所以决策时,每次都要用到前面的数据,但前面的数据又不能被改过。所以可以从后往前,可以确保你要决策的数,只被决策一次。
import java.io.*;
public class Main
{static int N = 1010;static int V;static int n;static int[] f = new int[N]; //只选前i件物品,背包容量为j的最优解static int[] v = new int[N]; //存体积static int[] w = new int[N]; //存价值static BufferedReader in = new BufferedReader(new InputStreamReader(System.in));public static void main(String[] args)throws IOException{String[] init = in.readLine().split(" ");n = Integer.parseInt(init[0]);V = Integer.parseInt(init[1]);for(int i = 1;i <= n;i++){String[] data = in.readLine().split(" "); v[i] = Integer.parseInt(data[0]);w[i] = Integer.parseInt(data[1]);}for(int i = 1;i <= n;i++){ //从后往前决策, j < v[i] 的地方不需要更新,直接用上一次的数据for(int j = V;j >= v[i];j--){f[j] = Math.max(f[j],f[j-v[i]]+w[i]);}}System.out.println(f[V]);in.close();}
}