填坑行动3-背包DP

01背包

01背包可以说是比较经典的一个算法了,它是动态规划的精髓。01背包问题一般是一个这样的问题:

N N N种物品,每种物品的体积分别为 w i w_i wi,价值分别为 C i C_i Ci每种物品只能拿一次。 有一个体积为 M M M的背包。请问背包能带走最大的价值是多少?

一般人会想到用贪心来做,但是,贪心往往是错误的。看一下一组数据:
N = 3 N=3 N=3
M = 5 M=5 M=5
W = { 4 , 3 , 2 } W=\{4,3,2\} W={4,3,2}
C = { 7 , 5 , 3 } C=\{7,5,3\} C={7,5,3}
显然答案是 8 8 8,但是用贪心的话答案就是 7 7 7,所以贪心是错误的。
那么该怎么做呢? O ( 2 n ) O\left( 2^n\right) O(2n)肯定会T飞,那么该肿么办呢?

算法解析

f i , j f_{i,j} fi,j为当背包体积为 j j j的时候,有 i i i件物品时所带走最大的价值。显然有两种做法:不取、取。
如果不取,那么值就是 f i − 1 , j f_{i-1,j} fi1,j
如果取,那么就要在背包内挖出一块 w i w_i wi的空间来存储,还要加上 c i c_i ci。值就是 f i − 1 , j − w i + c i f_{i-1,j-w_i}+c_i fi1,jwi+ci。当然还有满足 w i ≤ j w_i\leq j wij
综上得 f i , j = max ⁡ ( f i − 1 , j , f i − 1 , j − w i + c i ) f_{i,j}=\max\left(f_{i-1,j},f_{i-1,j-w_i}+c_i\right) fi,j=max(fi1,j,fi1,jwi+ci)

复杂度分析

给出一个代码

int f[maxn][maxn];
//读入已省略
for(i=1;i<=m;i++) f[1][i]=0;
for(int i=1;i<=n;i++)
    for(int j=1;j<=m;j++)
        if(j>=w[i])
            f[i][j]=max(f[i-1][j],f[i-1][j-w[i]]+c[i]);
        else f[i][j]=f[i-1][j];

显然我们可以发现空间复杂度为 O ( M N ) O \left(MN\right) O(MN)。时间复杂度也是 O ( M N ) O \left(MN\right) O(MN)

空间优化

有些时候当 M N MN MN比较大的时候,我们需要进行空间优化。
我们发现,要得到 f i f_i fi这一行,只需要得到 f i − 1 f_{i-1} fi1就可以了,我们就可以开一个数组int f[2][maxn]就够了。
当然,我们可以直接开一个一维数组,只不过需要从后往前更新,至于原因…我懒得说

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值