背包问题:在有限背包容量的情况下选择总价值最大的物品装入背包
用动态规划来解决背包问题,要理解dp[i][j]数组表示的含义:它表示背包可装入体积为j的情况下考虑是否可以装入第i个物品,以及要不要装入第i个物品。dp[i][j] 存的是当前最大总价值。
我的理解是:分两步来考虑,dp[i][j]就是针对第i个物品考虑【能不能】装入和【要不要】装入这两个问题
【能不能】装入就是看当前背包容量 j 是否大于等于第i个物品的体积,如果大于就表示第i个物品可以装入,也就是说,此时背包中可以预留出装入第i个物品的体积
【要不要】装入就是看装入第i个物品之后的总价值dp[ i ][ j ]是否增加,也就是说选取最大的dp[ i ][ j ],那么就考虑一下不装第 i 个物品的总价值如何表示,装入第 i 个物品之后的总价值如何表示就可以了
如果不装第i个物品,那么此时的总价值还是前 i-1个物品的总价值,在数组上表示为dp[i-1][j]
如果装第i个物品,先预留出第i个物品的体积,那么剩下的体积为j-v[i], 查表找到前i-1个物品,在体积为j-v[i]的情况下的价值(在数组上表示为dp[ i-1 ][ j-v[i] ]),然后加上第i个物品的价值,就是装入第i个物品之后的总价值了,即为 dp[ i-1 ][ j-v[i] ] + w[i]
dp[ i ][ j ]选取两者最大值。
代码如下:
import java.util.*;
public class DP {
static int N = 1010;
static int[] v = new int[N];
static int[] w= new int[N];
static int[][] dp = new int [N][N];
public static void main(String args[]) {
/**
* 01背包问题 有 N 件物品和一个容量是 V 的背包。每件物品只能使用一次。
*
* 第 i 件物品的体积是 vi,价值是 wi。
*
* 求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。 输出最大价值。
*/
Scanner sc = new Scanner(System.in);
int n , bagV;
n = sc.nextInt();
bagV = sc.nextInt();
// 输入n个物品的体积和价值
for( int i = 1; i <= n ; i++) {
v[i] = sc.nextInt();
w[i] = sc.nextInt();
}
// 动态规划
// i控制第几个物品,就是只考虑i之前(包括i)的物品
for ( int i = 1; i <= n; i++) {
// 然后用j控制当前背包容量
// j要小于背包总容量bagV
for ( int j = 1; j <= bagV; j++) {
// 刚开始的背包的dp是和前一行的一样,
// 因为还没有开始考虑当前第i个物品呢,相当于就没有将第i个装进去
// 也就是说现在的dp还是和前i-1个物品的dp一样
dp[i][j] = dp[i-1][j];
// 现在要考虑[能不能]装第i个物品了
// 不要忘记等号
if (j >= v[i]) { // 就是说当前的背包容量j大于第i个物品的体积,也就是说可以预留出体积来装第i个物品
// 既然能装,那就要考虑[要不要]装第i个物品了
// 背包问题是要在体积允许的情况下装入最大价值的物品且每个物品只能选择一次
// 所以[要不要]装第i个物品的关键就是比较一下装入第i个物品之后的价值和前i-1个物品的价值的大小关系即可
// dp[ i-1 ][ j ] 表示不装第i个物品的总价值
// dp[ i-1 ][ j-v[i] ] + w[i] 表示装入第i个物品的总价值:先预留出装第i个物品的体积,剩余体积为j-v[i],
// 查表找到前i-1个物品,在体积为j-v[i]的情况下的价值,然后加上第i个物品的价值,就是装入第i个物品之后的总价值了
dp[i][j] = Math.max(dp[ i-1 ][ j ], dp[ i-1 ][ j-v[i] ] + w[i]);
}
}
}
System.out.println("背包的最大价值为: " + dp[n][bagV]);
sc.close();
}
}