小白专题之01背包

小白专题之01背包

一.题目介绍:
有n件物品和一个承重为M的背包。(每种物品均只有一件)第i件物品的重量是w[i],价值是v[i]。求解将哪些物品装入背包可使价值总和最大。(0-1背包问题有两类,分别是最后可能未装满和最终恰好装满。本文章只是探讨可能未装满的状况。)
  • 基本思想:动态规划

动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中,可能会有许多可行解。每一个解都对应于一个值,我们希望找到具有最优值的解。动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适合于用动态规划求解的问题,经分解得到子问题往往不是互相独立的。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算了很多次。如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。我们可以用一个表来记录所有已解的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。这就是动态规划法的基本思路。

  • 一个重要的方程
    我们用f[i][j]来表示前i个物品装入j容量的背包所能获得的最大价值。为了方便,我们用w(weight)来表示物品的重量,用v(value)来表示物品的价值。接下来我们引出这个算式,也叫状态转移方程(采用动态分析,状态转移方程很重要)
    f[i][j]=max{f[i-1][j],f[i-1][j-w[i]]+v[i]}

我们要计算f[i][j],对于第i个物品,他要么放入背包,要么不放入背包,只有两个状态。
(1)如果不放入背包,那么f[i][j]=f[i-1][j];
(2)如果放入背包,那么f[i][j]= f[i-1][j-w[i]]+v[i]。f[i-1][j-w[i]]表示前i-1个物品在(总容量-第i个物品的重量)的情况下的最大价值,再加上p[i]即第i个物品的价值那么就等于前i个物品的总价值。

二:详细过程分析

二维数组理解容易,写起来并不难。为了方便大家和后边将要讲到的一维数组比较,我在此特意供上例子,表格以及详细的过程(或是如果大家对二维比较清楚的话可以直接看一维)。
题目:一个背包承重8Kg,有三件物品质量分别为3Kg4kg,5kg,对应的价值为4元,5元,6元,问在不超出背包承重范围的情况下,如何装配能获得最大价值?
如图所示
如图所示,表格中的黑色数字代表在目前状态的承重以及能放的物品数量下,所能达到的最大价值。即f[i][j]代表在j的承重条件下,选择放进前i个物品的任意几个的最大价值。
我们可以先看一下代码,然后我按照代码的流程写一下详细的计算过程你应该就明白了。

for(i=1;i<=3;i++)              \\我直接用数表示了,这样方便
   for(j=1;j<=8;j++)
{
    if(w[i]>j)
    f[i][j]=f[i-1][j];
    else
    f[i][j]=max{f[i-1][j],f[i-1][j-w[i]]+v[i]};
}
我写一下部分的计算过程:
    i=1,j=1:  w[1]=3>j=1,f[1][1]=f[0][1]=0             //要注意初始的二维数组元素均为0
    以下我再简单写几个吧:
    i=1,j=3:     f[1][3]=max{f[0][3],f[0][0]+4}=max{0,4}=4
    i=1,j=7:     f[1][7]=max{f[0][7],f[0][4]+4}=max{0,4}=4
    i=2,j=3:     w[2]=4>j=3,f[2][3]=f[1][3]=4
    i=2,j=7:     w[2]<j, f[2][7]=max{f[1][7],f[1][3]+5}=max{4,4+5}=9 

如果你上面的过程还是有点迷糊,我建议你可以动手写一下。我们发现不管你想求前几个物品在什么承重下的最大价值都可以求出来,他们对应的数值储存在二维数组中(这也是二维和一维的差别)

三.优化成一维数组

我们要知道,不管是二维数组还是一维数组,我们在表格中都是一行一行去计算的,而且下面一行的数据是和上面一行的数据息息相关的,我们在二维数组中,用到了i变量和j变量,f[i][j]代表前i个物品在j承重条件下的最大价值,我们其实完全可以不用i变量,因为我们本身就是一行一行更新的,当我们计算完第一行,计算第二行时,第二行的数据就会把第一行给破坏掉而形成最新的数据。

for(i=1;i<=3;i++)
    for(j=8;j>=w[i];j--)    \\为了方便 这里的38依旧是题目原数
        f[j]=max{f[j],f[j-w[i]]+v[i]};

表格还是上面的表格,不过这个时候第二次循环已经是逆序的了,即每行从后面往前更新。

**依旧是看一下详细的过程**~~~
i=1时
f[7]=max{f[8],f[5]+4}=4              \\一维数组的初始值为0
f[7]=max{f[7],f[4]+4}=4   
f[6]=f[5]=f[4]=4也是前边的算法
f[3]=max{f[3],f[0]+4}=4
f[2]则因为w[1]=3>j=2所以f[2]=f[1]=0
i=2时:
f[8]=max{f[8],f[4]+5}=max{4,9}=9      \\注意这一段的不同,我们可以发现新的f[j]会把旧的f[j]替换掉,左右两边的f[8]不是一样的,右边的f[8]实际上是前1个物品装入背包的最大价值,左边的f[8]代表前2个物品装入背包的最大价值。(一定要理解这里)
f[7]=max{f[7],f[3]+5}=9
f[6]=max{f[6],f[2]+5}=max{4,5}=5     \\实际上不管是左边还是右边f[j]均可在表格中找到,你要知道如何去找
i=3时:
f[8]=max{f[8],f[3]+6}=10
总结一下一维数组与二维的不同:
  • 首先,当进行第i次循环时,f[j]中保存了上一次循环的结果,也就是说在f[j]=max{f[j],f[j-w[i]]+v[i]}中,右侧的数据都是已经计算出的结果.
  • 其次,你要知道,只有利用了J的逆序运算,我们才可以保证上一次循环的数据的完整,否则还没进行下一次循环,数据就被破坏了。
  • 对于f[j]=max{f[j],f[j-w[i]]+v[i]}这个式子,我们应该知道右侧的f[j]其实就相当于二维数组的f[i-1][j],f[j-w[i]]+v[i]就相当于二维数组的f[i-1][j-w[i]]+v[i]。
  • 另外还需要说明,下面一行的数据一定大于等于上边一行(由方程也可以看出来),所以当我们用一维数组的时候,只要我们输入承重M,因为他的循环次数由n决定,所以f[M]就可以代表把这n个物品放入背包的最大利益。

以后的01背包问题都可以用一维去解决,而且这对理解后面的背包问题也很有好处,如果文章对大家有帮助,还望多多支持!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值