0-1背包和完全背包是如何从二维数组压缩到一维数组的

  0/1背包的主要思路就是:这件物品,取还是不取。用一个二维数组dp[i][v]来表示对第i个物品,背包容量为v时的情况。c[i]表示第i件物品的体积,w[i]表示第i件物品的价值。那么考虑第i件物品取与不取:如果不取,那么就可以转化为i-1件物品、容量仍然为v、价值没有增加的情况(dp[i-1][v]);如果取,那么转化为i-1件物品、容量减去第i件物品的体积后剩余容量、价值加上第i件物品的价值后的情况(dp[i-1][ v-c[i] ] + w[i] )。为了让背包中物品价值最大,我们取二者较大者,也就是

dp[i][v]=max{ dp[i-1][v] , dp[i-1][ v-c[i] ] + w[i] }。好了,现在思考如何将数组压缩,对于这两种情况下dp[i][v]值的改变,要么是dp[i][v]=dp[i-1][v],要么是dp[i][v]=dp[i-1][ v-c[i] ] + w[i]。假设下面是就是二维数组dp的一部分,

      a    b    dp[i-1][v]    d    e

      f    g     dp[i][v]       h          k

  我们可以发现:如果dp[i][v]=dp[i-1][v],那么相当于直接复制dp[i][v]上面的元素dp[i-1][v]值。而如果dp[i][v]=dp[i-1][ v-c[i] ] + w[i],注意到,v-c[i]<=v,所以,dp[i][v]的值是由上面红色的元素加上w[i]得到,也就是说,我们每次想要更新dp[i][v],可能会用到的值只有上面红色的部分,所以,我们就能把二维数组压缩为一维数组,只需要每次从后往前更新dp[i][v]的值。这样就用dp[v]来表示容量为v的情况下,背包内物品的价值,状态转移方程也就成了:

  dp[v]=max{ dp[v] , dp[ v-c[i] ] + w[i] }

 

  对于完全背包,一件物品可以取多次,我们仍然使用0/1背包的思想:这件物品,取还是不取。唯一的变化是,取了这件物品,还可以取。所以,如果取,仍然是i件物品的问题( dp[i][ v - c[i]] + w[i]);如果不取,dp[i][v]还是dp[i-1][v]都一样(第一次不取,以后也不会取,相当于转化成i-1件物品的问题,为了和取的情况保持一致,采用dp[i][v])。所以状态转移方程变为了dp[i][v]=max{ dp[i][v] , dp[i][ v-c[i] ] + w[i] },那么在数组里,

      a    b    m        d    e

      f    g     dp[i][v]       h          k

  同样注意到,v-c[i]<=v,所以,每次更新dp[i][v],可能用到的值是红色部分,所以也可以压缩为一维,这里要注意了,数组中的f、g,是i下的情况,并不是i-1的情况,dp[i][v]的值取决取i下,而不是i-1,所以此时应该从前往后更新dp的值,这样才能保证取第i件物品时,dp[i][v]是由dp[i][v-c[i]]+w[i]推得,所以尽管状态转移方程仍然为dp[v]=max{ dp[v] , dp[ v-c[i] ] + w[i] },v的循环顺序却应该是从小到大

 

  基本上,这就是0/1背包和完全背包从二维转化为一维的思路,以后自己还要经常复习。

  0/1背包的伪代码:

for i=1 to N
    for v=V to 0
        f[v]=max{dp[v],dp[v-c[i]]+w[i]}

  完全背包的伪代码:

for i=1 to N
    for v=0 to V
        f[v]=max{dp[v],dp[v-c[i]]+w[i]}
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值