首页 动态规划
文章
取消

动态规划

01背包问题

需要注意的问题:

  1. 对于01背包问题:每一件物品,要么不放要么只放一次
  2. 对于dp二维数组,第一维应该是物品数量,第二维才是体积或者重量
  3. 对于物品数量,遍历应该从1开始,并且dp【i】【w】 = Math.max(dp【i-1】【w】, dp【i-1】【w-vw【i】【0】】 + vw【i】【1】),解释:dp【i】【w】,代表背包容量为w时,物品陈列为0~i-1这几个物品时背包所能装的最大重量,vw【i】【0】代表物品i-1的体积,vw【i】【1】代表物品i-1的重量。

思路:

  1. 首先对dp数组进行初始化,要想得到最终的结果,我们就要知道子问题的结果,例如上面提到的:如果要求得dp【i】【w】的值首先得知道dp【i-1】【w-vw【i】【0】】的值
  2. 对于物品i,实际有两种选择,第一种不放(包括背包容量不足以装下i),对于二维数组来说值就是当前列的上一行dp【i-1】【w】,第二种放:如果容量足够,那么就可以放,这时候的值应该是减掉物品i占用的体积所能放的最大重量加上物品i的重量,而最终还要比较在这种情况下,不放和放哪个大,取最大的哪个,之所以要比是因为:如果两个物品i-1和i,它们体积相同,质量不同,而且背包也只能装一个,那么最后就需要比较放i和不放i哪个大了
  3. 最后返回父问题的结果就ok了
  4. 当然如果理解起来很困难,那就将二维数组画成一个表格,从左到右,从上到下依次填充,不过实际上没必要这样,因为这种问题有点递归的意思在里面,正如对于递归没必要对每个细节都清楚,我们只需要知道递归做的工作是什么,边界值是什么,返回什么就行了,对于01背包也是,我们不用知道子问题最后的值是什么,我们只要知道父问题是子问题的值比较出来的就行了

真题链接:

NC145 01背包

解答:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
 * 代码中的类名、方法名、参数名已经指定,请勿修改,直接返回方法规定的值即可
 * 计算01背包问题的结果
 * @param V int整型 背包的体积
 * @param n int整型 物品的个数
 * @param vw int整型二维数组 第一维度为n,第二维度为2的二维数组,vw[i][0],vw[i][1]分别描述i+1个物品的vi,wi
 * @return int整型
 */
public int knapsack (int V, int n, int[][] vw) {
   // write code here
   int[][] dp = new int[n+1][V+1];
   //i=0的时候代表没有物品,这时候不管背包的容量为多少,实际背包装的最大重量都应该为0
   for(int i = 1; i<=n;i++){
       //当背包容量为0的时候,不管有多少物品,背包都装不下,所以也是0
       for(int j = 1;j<=V;j++){
           if(j<vw[i-1][0]){
               dp[i][j] = dp[i-1][j];
           }else{
               dp[i][j] = Math.max(dp[i-1][j],dp[i-1][j-vw[i-1][0]]+vw[i-1][1]);
           }
       }
   }
   return dp[n][V];
}
本文由作者按照 CC BY 4.0 进行授权