背包问题

背包问题

01背包

问题:给一个容量为V的背包,以及N个物品,每个物品的体积是ci,价值是wi,将那些物品放到背包中能使得价值之和最大,求这个最大值。

思路:设dp[i][v]为前 i种物品放到容量为v的背包中能得到的最大价值。
由于第i个物品要么放入背包要么不放入,所以状态转移方程为 dp[i][v]=max(dp[i-1][v],dp[i-1][v-ci])

复杂度:使用滚动数组优化空间复杂度为O(V),时间复杂度为O(N*V)

关键代码:

for(int i=1;i<=n;i++)
        for(int j=c[i];j<=v;j++)
        dp[i][j]=max(dp[i-1][j],dp[i-1][j-c[i]+w[i]);
for(int i=1;i<=n;i++)
        for(int j=v;j>=c[i];j--)
        dp[j]=max(dp[j],dp[j-c[i]]+w[i]);
完全背包

问题:和01背包的不同之处就是每件物品的个数是无限的

思路1:转换成01背包。
尽管每件物品的个数是无限的,但是背包的容量是有限的,所以每件物品其实最多只能放V/ci个。每件物品最终在背包中的数量都可以表示成2^k 的和(2进制表示),所以每件物品都可以被换成多个01背包中的物品,它们的体积和价值分别为(2^k )*ci和(2^k )*wi。每个物品都转换成log2(V/ci)件01背包中的物品,然后就可以使用01背包的方法解决问题了。

思路2:dp[i][v]还是表示前 i种物品放到容量为v的背包中能得到的最大价值。由于第i件物品可以不放也可以放多次,所以dp[i][v]可以由dp[i-1][v] (第i件物品没有放)和dp[i][v-ci]+wi (第i件物品至少放了多件,至少1件)转换来, 所以得到状态转换方程为 dp[i][v]=max(dp[i-1][v],dp[i][v-ci]+wi)。

思路2的关键代码:
思路2也可以使用滚动数组来优化空间复杂度,不使用滚动数组的代码就不帖了。

for(int i=1;i<=n;i++)
        for(int j=c[i];j<=v;j++)
        dp[j]=max(dp[j],dp[j-c[i]]+w[i]);

思路2的时间复杂度比思路1的要小,处理一件物品的时间复杂度为O(V),总的时间复杂度为O(N*V)。二思路1处理一件物品的时间复杂度为O(V*log2(V/ci)),总的复杂度为O(N*V*∑log2(V/ci))

多重背包

问题: 和完全背包问题不同,多重背包中,每个物品的个数并不是无限的,最多mi件。

思路1:和完全背包一样可以将每件物品转换成多件01背包中的物品,然后使用01背包的方法来解决。(处理每件物品的时间复杂度为O( V*log2(mi) ) 。)

思路2:可以使用01背包和完全背包的混合来解决,当mi*c i< V 时,将这件物品转换成多个01背包中的物品再来处理;当mi*ci>=V时使用完全背包的方法来处理这件物品。(当mi*c i< V 时处理一件物品的时间复杂度为O( V*log2(mi) ),但是当mi*ci>=V时,处理一件物品的时间复杂度可以变为O(V),见前面完全背包)

思路2要比思路1的时间复杂度更小

这里只是粗略地写了一篇关于背包问题的博客,主要用于我个人学习,勿喷。
背包问题还有很多内容(前三种的组合、分组背包问题、具有依赖关系的背包问题、二维背包问题。。。。。。),感兴趣的可以自行去看背包九讲。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值