动态规划之背包问题

动态规划之背包问题
1.01背包问题
  • 题目描述:

有N件物品和一个容量为V的背包。放入第 i i 件物品耗费的空间是Ci ,得到的价值是 Wi W i ,求解将哪些物品装入背包可使价值总和最大。

  • 状态转移方程:

F[i][v] F [ i ] [ v ] = max(F[i1][v],F[i1][vCi]+Wi) m a x ( F [ i − 1 ] [ v ] , F [ i − 1 ] [ v − C i ] + W i )

i1 i − 1 ,重量为 v v 的状态下,放或者不放第i件物品。

  • 将二维转化至一维可得伪代码:复杂度: O(VN) O ( V N )
void ZeroOnePack(F,C,W)
{
    for v = V to C //从V到C是进行了优化
       F[v]=max{F[v],F[v-C]+W};
}
for i = 1 to N 
    ZeroOnePack(F,C[i],W[i]);
  • 初始化的细节问题:

如果要求恰好装满背包,则初始化时, F[0]=0 F [ 0 ] = 0 ,其余 F[1V]= F [ 1 … … V ] = − ∞

若未要求恰好装满,则 F[0V]=0 F [ 0 … … V ] = 0

  • 个人对于代码的理解:

i i 从1到n刷新数组,所以每一个i在使用数组时,都有 i1 i − 1 使用过的痕迹,所以起到了状态的限制。

另外, v v 从V到0,当计算较大的v时,较小的 v v 还没有放入i,所以保证了所有的物品只被放入一次。

2.完全背包问题
  • 题目描述:

有N种物品和一个容量为 V V 的背包,每种物品都有无限件可以用,放入第i件物品耗费的空间是 Ci C i ,得到的价值是 Wi W i 。求解:将哪些物品放入背包,可使这些物品耗费的空间总和不超过背包的容量,且价值总和最大。

  • 状态转移方程:

F[i][v] F [ i ] [ v ] = max(F[i1][v],F[i1][vkCi]+kWi) m a x ( F [ i − 1 ] [ v ] , F [ i − 1 ] [ v − k ∗ C i ] + k ∗ W i )

F[i][v] F [ i ] [ v ] = max(F[i1][v],F[i][vCi]+Wi) m a x ( F [ i − 1 ] [ v ] , F [ i ] [ v − C i ] + W i )

  • 可能的优化方法:

去掉重量大于V的,对于cost相同的物品,只选择weight最大的

  • 伪代码: O(VN) O ( V N )
void CompletePack(F,C,W)
{
    for v = C to V 
       F[v]=max{F[v],F[v-C]+W};
}
for i = 1 to N 
    CompletePack(F,C[i],W[i]);
  • 个人对于代码的理解:

使 v v 从C到V,当v较大时,较小的 v v 已经被更新过,所以相当于可以重复往背包里放入同一个物体。

3.多重背包问题
  • 题目描述:

有N件物品和一个容量为V的背包。第i种物品最多有 Mi M i 件可用,每件耗费的空间是 Ci C i ,价值是 Wi W i 。求解将哪些物品装入背包可使这些物品耗费的空间总和不超过背包容量,且价值总和最大。

  • 状态转移方程:

F[i][v] F [ i ] [ v ] = max(F[i1][v],F[i1][vkCi]+kWi)0kMi m a x ( F [ i − 1 ] [ v ] , F [ i − 1 ] [ v − k ∗ C i ] + k ∗ W i ) 0 ≤ k ≤ M i

  • 伪代码: O(VlogMi) O ( V ∑ l o g M i )
void MultiplePack(F,C,W,M)
{
  if(C*M>=V){
    CompletePack(F,C,W);
    return ;
  }
  k=1;
  while(k<M){
    ZeroOnePack(F,k*C,k*W);
    M=M-k;
    k=k*2;
    ZeroOnePack(F,M*C,M*W);
  }
}
  • 代码理解:

将多重背包转化为完全背包和01背包。如果物品对于背包不能视作完全,就将物品拆成1,2,4,8……的01背包。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值