完全背包与01背包

在做动态规划问题的时候,感觉尤为抽象。背包问题作为动态规划的经典问题,直接记公式倒是很好记,但是总感觉无法将其灵活运用,而只有将其过程完完全全都在脑子里呈现出来了,才能有更深的理解。现在趁着这个机会好好将经典的完全背包和01背包做个总结。

可预先参考:背包问题超详解 - 知乎

背包问题 - 知乎

leetcode动态规划入门系列总结_qq_42987967的博客-CSDN博客

一、01背包

1.问题定义:

2.转移方程分析

这个转移的状态V[i][j]的含义即在考虑第0--i个物品时,容量为j的背包所能承载的最大价值。 

首先,当背包容量j<v[i]的时候(即考虑背包只装i,但是i还是装不下的情况),那么这个背包是肯定装不下物品i的,因此其最大价值是由V[i-1][j]转移来的。

否则,V[i-1][j]可能是由V[i-1][j]或者V[i-1][j-w[i]]+w[i]中的较大者转移来的(转移方程具有贪心思想)。

现在打个表距离分析:假设有三件物品,背包容量为14,重量数组v{1,2,5},价值数组w{2,3,4},

 结合状态表能比较好地理解转移方程的含义。并且我们通常会在状态表中插入i=0和j=0作为初始化转移条件。

并且容易观察得出其实V[i][j]在j=所有物品的重量总和后,便不再增加了。

3.状态压缩

考虑到第i次的转移方程只与第i-1次的状态有关,因此可以进行状态压缩。

二、完全背包

1.爬楼梯跟斐波那契数列

斐波那契数列跟爬楼梯都是经典的动态规划入门题,先拿来开开胃:

其有递推公式:

f(k)=f(k-1)+f(k-2)

即代表着第k个状态可以由第k-1个状态跟第k-2个状态转移而来。因此用递归法可以这样写:

    int climbStairs(int n) {
        if(n==1)return 1;
        if(n==2)return 2;
        return climbStairs(n-1)+climbStairs(n-2);
    }

也可以用迭代法:

    int climbStairs(int n) {
        if(n==1)return 1;
        if(n==2)return 2;
        int fk1=1,fk2=2,ans;
        for(int i=0;i<n-2;i++)
        {
            ans=fk1+fk2;
            fk1=fk2;
            fk2=ans;
        }
        return ans;
    }

2.完全背包

 可以看出这个与01背包的区别在于物品是能取不限次的,而01背包是可以一件物品只能取一次。

 这个问题咋一看还挺抽象的,脑子里不停地想着暴力解法,然后一运行,直接超时。

3.转移方程分析

 相比01背包,完全背包的转移方程更复杂些。同样,这个转移方程也可以做状态压缩,具体就参考背包问题 - 知乎

『 一文搞懂完全背包问题 』从0-1背包到完全背包,逐层深入+推导

 4.先遍历容量还是先遍历物品

为了先跟前面的爬楼梯问题结合起来,体验一个从一般到抽象的过程,将爬楼梯问题转化为完全背包问题的描述:

有两种物品,第一种物品体积是1,第二种物品体积是2,价值都是1,

背包容量是k,请问能组成的最大价值。

而我们在爬楼梯这道题其实用的是先遍历容量再遍历物品的。而也只有完全背包才能先遍历容量再遍历物品,这是因为完全背包是不限制选取次数的。

即有f(k)=max(f(k-w[i]),f(k-w[i+1]...)

推荐习题:

面试题 08.11. 硬币

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值