完全背包问题

引言

完全背包和01背包最大的区别就是:完全背包中装背包的物品可以重复使用多次
这里还是拿经典的背包问题论述;

问题:有N件物品和一个最多能背重量为W的背包。第i件物品的重量是weight[i],得到的价值是value[i] 。每件物品都有无限个(也就是可以放入背包多次),求解将哪些物品装入背包里物品价值总和最大。

这就是完全背包问题,但是其实和01背包就区别在每种物品有无限件。其他几乎一模一样,
那么这道题该怎么解决呢?
步骤和01背包一样,这里只说区分点:
不同之处就在于循环顺序上
01背包内部的循环是从大到小倒序遍历,为了保证每个物品仅被添加一次。
代码如下:

 for(int i = 0; i < weight.size(); i++) { // 遍历每一件物品
        for(int j = bagsize; j >= weight[i]; j--) { // 遍历不同的背包容量
            dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
        }

因为完全背包每个物品可以添加多次,所以内部循环就不能从大到小遍历了,正序遍历就可以了,否则就不符合题意了
代码如下:

for(int i = 0; i < weight.size(); i++) { // 遍历每一件物品
    for(int j = weight[i]; j < bagWeight ; j++) { // 遍历不同背包容量
        dp[j] = max(dp[j], dp[j - weight[i]] + value[i]);
    }
}

当然这里同样会出现一个问题,这个循环内外两层可以交换位置吗
在这个完全背包问题中,不论怎么交换位置,对结果都是没有影响的,
但是,因为这是纯粹的完全背包问题,所以没有影响,

如果问装满背包有几种方式的话?那么两个for循环的先后顺序就有很大区别了;
求方式数就是求组合数,而有的题目会让我们求排序数,一定要注意这两者的区分,
组合不强调元素之间的顺序,排列强调元素之间的顺序

就比如:1 1 2 3 和 1 2 3 1
这是一种组合,因为里面元素都是一样的
这是两种排序,因为里面元素顺序都不同

那么求组合数和排列数的遍历顺序又是怎样呢?
只需要记住下面两点:

如果求组合数就是外层for循环遍历物品,内层for遍历背包容量。
如果求排列数就是外层for遍历背包容量,内层for循环遍历物品。

这里有两道很简单的题目可以感受一下这两种问题的区别:
求组合数:零钱兑换II
求排列数:爬楼梯

总结

其实完全背包问题也就几点注意,整理一下:

1,背包容量的循环是正序的,因为一个物品要加很多次
2,纯完全背包问题:物体和背包容量的内外循环顺序可以随意改变
3,求组和数类问题:外循环是物品,内循环是背包容量(保证每个物品在不同容量背包中出现次序只为一次)
4,求排列数类问题:外循环是背包容量,内循环是物品(每个背包容量下将各种情况都概括)
一定要清楚排列和组合的区别

同时在这里也把01背包规整一下做个对比

1,背包容量的循环是倒序的,因为一个物品只能加一次
2,如果dp是二维定义的(优化前),则内外循环顺序没有关系,都可以
3,如果dp是一维定义的(优化后),则需要注意:
外循环是物品,内循环是背包容量,且内外循环能不能交换位置;

这些都是要注意的地方,在做题或者面试时都有可能遇到,所以还是需要理解掌握;

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

YXXYX

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值