动态规划--背包问题的另一种通俗理解(C++)

动态规划的入门可以先看这篇文章:动态规划入门

背包问题是动态规划中最经典的一个问题,要是比较难的一个问题。

题目:

有一个背包,它的容量为C(Capacity),现在有n种不同的物品,编号为0…n-1,其中每一件物品的重量为w(i),价值为v(i)。问可以向这个背包中盛放哪些物品,使得在不超过背包容量的基础上,物品的总价值最大。

别看下面我讲的了,只用看下面这个视频就好了,讲的非常清楚!
背包问题解析

题目解析:

变量: C(容量) i(第i个物品) w(i) (第i件物品的重量) v(i)(第i件物品的价值)
要求:
(1) w(0)+w(1)+…w(i-1)<=C
(2)v(0)+v(1)+…v(i-1)价值最大【 (2) v(0)+v(1)+…v(i-1)> v(0)+v(1)+…v(i-2)(错误)
因为i代表是第i个物品,而第一个物品的编号是0,所以注意最后下表要减一

思想理解:
注意:题目中说让物品的总价值最大,并不是说尽最大可能把背包装满同时不超过最大容量就行,而是尽可能挑选出那些高性价比(低容量高价值)的优先装。为了使背包里的价值最大,有些物品需要放进去,有些物品不需要放进去,因为有些物品可能会因为重量大价值又小使得性价比太低,比如背包容量是5,有5个价值为10重量为1的物品,还有一个价值为1容量为5的物品,如果选择了将后者放到背包里,就放不进去其他物品,导致最终的价值极低。

看了很多百度的回答解释,几乎都是这么分类:
1.不放第i个物品,此时总价值为F(i-1,C)
2.放置第i个物品,此时总价值为v(i)+F(i-1,C-w(i))

所以,状态转移方程设成了这个样子:
在这里插入图片描述

理解这个方程真是费了老半天劲了!
这里起初有很多疑问:
i个物品放进容量为C的背包怎么可能等于i-1个物品放进容量为C的背包?
答:i代表是总共i个物品。当最后的第i个物品放不进去的时候,i个物品的价值就等于i-1个物品的价值。

如果是装不下了那第二个等于后面公式就是能装下的,能装下为什么是那样?
对,第二个不是能装下,而是必须装这第i个物品,装了之后再看剩下的空间装剩下的i-1个物品。

后期这两个等式进行比大小有什么意义?很明显只要容量够后面一定大于前面啊?
有意义,两者比较的是,不装第i个物品的价值和必须装第i个物品然后加上从剩下的空间里得出的最大价值。不装第i个物品的总数量i-1和装第i个物品之后的总数量i-1不是同一个东西。

有个大佬这么跟我解释:
这么分类的思想是利用递归,自顶向下的角度来看这个问题,也就是说,第n次放进去的物品可以影响第n-1次,但是第n-1次是不能影响第n次。

但是我还是有点想不通,于是换了一个思路:

接下来注意听我说:
不要看截图里面的解释,仅仅作为参考。
我们重新换一种新的理解:
F(n, C)表示从n件物品中,组合出x件(物品数量x可以大于n也可以小于n)价值最大且容量不超过C的物品放到背包中。

接下来寻找这些变量之间的一个等价关系。
在这里插入图片描述
这个等价关系应该怎样理解呢?注意听:

等式左边 F(i,c)表示从i件物品中挑出容量不小于c的组合的最大价值,它可能等于从i-1件物品中挑出容量不小于c的组合的最大价值,也就是说根本不用从i件物品里面选最大价值,没有你加入的最新的i件,同样可以挑出最大价值组合。

它也有可能等于,首先在最大价值组合里面,一定要把第i次挑出来的产品放进去。那这样,这个最大价值组合的其他元素只能在i-1件物品里面挑选容量之和不大于c-w(i)的物品,因为第i次挑选物品的确定,导致影响了在i-1件物品的挑选,所以出现F(i-1,c-w(i)),在i-1件物品中挑选出容量不大于c-w(i)的物品。

右边的两种情况,非常非常巧妙的利用了挑选物品一定算第i次挑选的物品和一定不算第i次挑选的物品这对互斥关系。最后从这两种组合中选出价值最大的那一个作为从i件物品中挑出的组大价值。

有了这个等价关系,接下来就是用递归–>记忆化递归–>动态规划的思想了,如果不明白这个套路可以看我之前的文章:5道题动态规划入门

首先最简单的递归:

#include <iostream>
#include <vector>
#include <cassert>
using namespace std;

/// 时间复杂度: O(n * C) 其中n为物品个数; C为背包容积
/// 空间复杂度: O(n * C)
class Knapsack01{
   
private:
    int bestValue(const vector<int> &w, const vector<int> &v, int index, int c){
   
       //递归的结束条件
        if(c <= 0 || index < 0)
            return 0;
        
        //第i个物品一定不放进最大价值组合里,此时的最大价值
        int res = bestValue(w, v, index - 1, c );
        //max的第二个参数就是一定选择第i个参数的情况
        if(c >= w[index])
        res = max(res, v[index] + bestValue(w, v, index - 1, c - w[index]));
        return res;
    }

public:
	//从这里开始看
	//w代表重量集合,v是对应的价值集合,C是容量
    int knapsack01
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值