背包问题总结

背包问题总结

首先,什么是背包问题呢?

背包问题的形式如下,给定 n n n个重量分别为 ω 1 , ω 2 , ⋯   , ω n \omega_1,\omega_2,\cdots,\omega_n ω1,ω2,,ωn,价值分别为 v 1 , v 2 , ⋯   , v n v_1,v_2,\cdots,v_n v1,v2,,vn的物品和容量为 C C C的背包,求这个物品中一个最有价值的子集,使得在满足背包的容量的前提下,包内的总价值最大。

其中,背包问题还有很多分类,咱们先从最基础的开始,0-1背包问题。该问题的要求是每个物品只能用一次。

刚才的叙述还是太抽象了。咱们再具体一下:

给定3个( n = 3 n=3 n=3)物品,每个物品的重量和价值分别如下:

物品序号重量价值
016
1210
2312

同时,背包容量为5( C = 5 C=5 C=5),求在重量之和小于背包容量的前提下,所选物品的价值最大。

0-1背包问题介绍完了,用什么方法解呢?

回溯法和动态规划法都可以,这里先用动态规划法来解一下。

什么是动态规划法呢?

简单来说就是,将一个问题拆成几个子问题,分别求解这些子问题,即可推断出大问题的解。这就是动态规划法。

还是有点抽象。咱们来具体一下。

对该问题,大问题就是,满足背包容量为5时,物品的最大价值。

子问题就是,背包容量为4时,物品的最大价值;背包容量为3时,物品的最大价值;一直到背包容量为0时,物品的最大价值。同时,还需要考虑题目的3个物品。所以,来建一个矩阵吧。

物品容量=0容量=1容量=2容量=3容量=4容量=5
0
1
2

这里需要对矩阵做一个说明:

第一行,代表背包的容量(假设的,不要产生这样的想法,题目中背包容量已经是5了,为什么背包容量还可以从0变到5呢,这里只是假设,或者说,背包中允许利用的容量),从0到5,

第一列,物品的三个编号,物品0,物品1,物品2

其余空间,在当前条件下,所选物品的最大价值。

顺便说一句,这个表格填完了,问题就解决完了。

如果要使用动态规划求解0-1背包问题,咱们需要先把矩阵的第一行填写完毕。第一行的含义是,对所有的背包容量,只放物品0,该物品的重量是1,价值是6,放的具体过程如下:

  • 容量=0,小于物品0 的重量1,放不下,最大价值为0
  • 容量=1,等于物品0的重量1,放的下,最大价值为6
  • 容量=2,小于物品0 的重量1,放的下,最大价值为6
  • 容量=3,等于物品0的重量1,放的下,最大价值为6
  • 容量=4,小于物品0 的重量1,放的下,最大价值为6
  • 容量=5,等于物品0的重量1,放的下,最大价值为6

所以,放完矩阵第一行后,矩阵如下:

物品容量=0容量=1容量=2容量=3容量=4容量=5
0066666
1
2

咱们先来看第一个小问题, C = 0 C=0 C=0,即背包所允许利用的最大容量为0,很容易理解,最大价值为0,所以,表格更新如下:

物品容量=0容量=1容量=2容量=3容量=4容量=5
0066666
10
20

接下来是第二个小问题, C = 1 C=1 C=1,即背包所允许利用的最大容量为1,这里再次给出物品的相关信息,希望读者将物品的相关信息写在纸上

物品序号重量价值
016
1210
2312

三个物品的重量分别是1,2,3,而背包容量是1,很容易分辨出,只能放物品0,最大价值是6,但是,计算机怎么分辨呢?动态规划最终还是要用编程语言来实现额啊。下面就是动态规划的核心的,状态转移方程
d p ( i , j ) = m a x ( d p ( i − 1 , j ) , d p ( i − 1 , j − w [ i ] ) + v [ i ] ) , j ≥ w [ i ] , i > 0 dp(i,j)=max(dp(i-1,j),dp(i-1,j-w[i])+v[i]),j\ge w[i],i>0 dp(i,j)=max(dp(i1,j),dp(i1,jw[i])+v[i]),jw[i],i>0
很多公式啊,咱们来理解一下:

  • dp代表咱们要填写的矩阵,为什么是dp呢,因为这两个字母是动态规划英文表达的缩写
  • d p ( i , j ) dp(i,j) dp(i,j)代表待求取位置的最大价值,对于咱们所处的这一步来说,i=1,j=1,因为填到物品1,容量=1了嘛,
  • max是求取最大值的操作
  • w [ i ] w[i] w[i]代表第i个物品的重量,此处,i=1, w [ i ] = 2 w[i]=2 w[i]=2
  • v [ i ] v[i] v[i]代表第i个物品的价值,此处,i=1, v [ i ] v[i] v[i]=10
  • 很容易添加限制条件, j ≥ w [ i ] j\ge w[i] jw[i],否则矩阵就越界了

公式介绍完了,那么对于咱们要填的这个空,怎么处理呢

  • i=1,j=1时,dp(i-1,j)=dp(0,1)=6,w[i]=w[1]=2>j=1,所以,dp(i,j)=dp(1,1)=max(dp(i-1,j))=dp(0,1)=6
  • i=2,j=1时,dp(i-1,j)=dp(1,1)=6,w[i]=w[2]=3>j=1,所以,dp(i,j)=dp(2,1)=max(dp(i-1,j))=dp(1,1)=6

此时,如果用一句话描述上面的公式就是,如果当前背包容量j小于物品的重量w[i],那么最大价值就等于上面那一格的值。填写后的矩阵如下:

物品容量=0容量=1容量=2容量=3容量=4容量=5
0066666
106
206

接下来是第三个小问题, C = 2 C=2 C=2,即背包所允许利用的最大容量是2,

  • i=1,j=2时,dp(i-1,j)=dp(0,2)=6,w[i]=w[1]=2=j=2,dp(i-1,j-w[i])=dp(1-1,2-2)=dp(0,0)=0,v[i]=v[1]=10,所以,dp(1,2)=max(dp(0,2)+dp(0,0)+v[1])=max(6,0+10)=10
  • i=2,j=2时,dp(i-1,j)=dp(1,2)=10,w[i]=w[2]=3>j=2,所以,dp(2,2)=dp(1,2)=10

什么规律呢,物品1的重量是2,那么dp(1,2)=max( dp(0,2) ,dp(0,0)+v[1]),即上面的那个格的值和上面一行,往左移动2个格(w[1]=2)的值的最大值

填写完后的矩阵如下:

物品容量=0容量=1容量=2容量=3容量=4容量=5
0066666
10610
20610

接下来是第三个小问题, C = 3 C=3 C=3,即背包所允许利用的最大容量是3,

  • i=1,j=3时,dp(i-1,j)=dp(0,3)=6,w[i]=w[1]=2<j=3,dp(i-1,j-w[i])=dp(1-1,3-2)=dp(0,1)=6,v[i]=v[1]=10,所以,dp(1,3)=max(dp(0,3)+dp(0,1)+v[1])=max(6,6+10)=16

  • i=2,j=3时,dp(i-1,j)=dp(1,3)=16,w[i]=w[2]=3=j=3,dp(i-1,j-w[i])=dp(2-1,3-3)=dp(1,0)=0,v[i]=v[2]=12,所以,

    dp(2,3)=max(dp(1,3)+dp(1,0)+v[2])=max(16,0+12)=16

填写完后的矩阵如下:

物品容量=0容量=1容量=2容量=3容量=4容量=5
0066666
1061016
2061016

接下来是第三个小问题, C = 4 C=4 C=4,即背包所允许利用的最大容量是4,

  • i=1,j=4时,dp(i-1,j)=dp(0,4)=6,w[i]=w[1]=2<j=4,dp(i-1,j-w[i])=dp(1-1,4-2)=dp(0,2)=6,v[i]=v[1]=10,所以,dp(1,3)=max(dp(0,4)+dp(0,2)+v[1])=max(6,6+10)=16

  • i=2,j=4时,dp(i-1,j)=dp(1,4)=16,w[i]=w[2]=3<j=4,dp(i-1,j-w[i])=dp(2-1,4-3)=dp(1,1)=6,v[i]=v[2]=12,所以,

    dp(2,3)=max(dp(1,4)+dp(1,1)+v[2])=max(16,6+12)=18

填写完后的矩阵如下:

物品容量=0容量=1容量=2容量=3容量=4容量=5
0066666
106101616
206101618

接下来是第三个小问题, C = 5 C=5 C=5,即背包所允许利用的最大容量是5,

  • i=1,j=5时,dp(i-1,j)=dp(0,5)=6,w[i]=w[1]=2<j=5,dp(i-1,j-w[i])=dp(1-1,5-2)=dp(0,3)=6,v[i]=v[1]=10,所以,dp(1,5)=max(dp(0,5)+dp(0,3)+v[1])=max(6,6+10)=16

  • i=2,j=5时,dp(i-1,j)=dp(1,5)=16,w[i]=w[2]=3<j=5,dp(i-1,j-w[i])=dp(2-1,5-3)=dp(1,2)=10,v[i]=v[2]=12,所以,

    dp(2,5)=max(dp(1,5)+dp(1,2)+v[2])=max(16,10+12)=22

填写完后的矩阵如下:

物品容量=0容量=1容量=2容量=3容量=4容量=5
0066666
10610161616
20610161822

终于写完了,总结一下公式的含义

上面的一个表格,上面那个表格往左数w[i]和表格,这两个表格的最大值就是要求的值。

解决代码如下:

public class KnapSack01 {
    public static int knapSack(int[] w, int[] v, int C) {
        int size = w.length;
        if (size == 0) {
            return 0;
        }

        int[][] dp = new int[size][C + 1];
        //初始化第一行
        //仅考虑容量为C的背包放第0个物品的情况
        for (int i = 0; i <= C; i++) {
            dp[0][i] = w[0] <= i ? v[0] : 0;
        }
		//填充其他行和列
        for (int i = 1; i < size; i++) {
            for (int j = 0; j <= C; j++) {
                dp[i][j] = dp[i - 1][j];
                if (w[i] <= j) {
                    dp[i][j] = Math.max(dp[i][j], v[i] + dp[i - 1][j - w[i]]);
                }
            }
        }
        return dp[size - 1][C];
    }

    public static void main(String[] args) {
        int[] w = {2, 1, 3, 2};
        int[] v = {12, 10, 20, 15};
        System.out.println(knapSack(w, v, 5));
    }
}


最后总结一下0-1背包问题的解题思路:

  • 建立矩阵dp,行数是物品的个数,列数是背包容量加1
  • 填写第一行,如果背包容量j小于物品重量w[0],最大价值是0,否则是第一个物品的价值v[0]
  • 填写接下来的每一行,首先判断背包容量j和第i个物品的重量w[i]的关系
    • 如果j<w[i],那么dp(i,j)=dp(i-1,j)
    • 如果j>=w[i],那么dp(i,j)=max( dp(i-1,j) ,dp(i-1,j-w[i])+v[i])
  • 返回矩阵右下角元素就是最大价值。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值