zoukankan      html  css  js  c++  java
  • 算法笔记----11.7.2 01背包问题

    https://www.cnblogs.com/DJC-BLOG/p/9416799.html

     

    算法解释起来太抽象了。也不是很好理解,最好的办法就是一步步写出来。

    背包问题的核心在于m[i][j]=max(m[i-1][j],m[i-1][j-w[i]]+v[i])这个公式理解起来还是有点麻烦的特别我这种脑子笨的人。所以我先上段代码,然后那数据一步步分析就行了。

    先上代码:代码稍微看看就行了,关键我下面的解释,走一遍就懂了。

     1 #include <iostream>
     2 #include<algorithm>
     3 using namespace std;
     4 const int N=15;//假设物品最多个数
     5 int v[N]={0,8,10,6,3,7,2};  //价格
     6 int w[N]={0,4,6,2,2,5,1};   //体积
     7 
     8 int main()
     9 {
    10     int m[N][N]={0};    //m[i][j]数组代表在第i件物品,背包容量为j时候能获得最大的价值
    11     int n=6,c=12;//设物品个数为6,背包容量为12
    12     for(int i=1;i<=n;i++)   //遍历物品个数
    13     {
    14         for(int j=1;j<=c;j++)//各种容量情况
    15         {
    16             if(j>=w[i])//若此时背包容量大于当前物品重量
    17                 //这里的m[i-1][j]就是第i-1个物品在j容量下的价值
    18                 //m[i-1][j-w[i]]这就是i-1个物品时候,背包容量为j-w[i]时候的最大价值
    19                 m[i][j]=max(m[i-1][j],m[i-1][j-w[i]]+v[i]);
    20             else//背包容量小于当前物品重量
    21                 m[i][j]=m[i-1][j];//维持第i-1个物品时候的背包重量
    22         }
    23     }
    24     for(int i=1;i<=n;i++)
    25     {
    26         for(int j=1;j<=c;j++)
    27         {
    28             cout<<m[i][j]<<' ';
    29         }
    30         cout<<endl;
    31     }
    32     return 0;
    33 }

     

     

    先解释下m[i][[j]的含义就是在i种物品的情况下,包容量为j的情况下,包内的最大价值。

    另外:这里的价值和体积一开始用00这是自己先加上去的,因为公式里面有个m[i-1][j],当i=1的时候m[0][j]就是当0种物品时候不管j等于多少肯定是0啦。

    好了接下来按照代码顺序来走一遍,走一遍就明白了。先上下数据表

    我们代码中设置的物品个数为6,背包容量为12

    m设[N][N]   N其实应该是max(物品个数,背包容量)。但是设大点又没事。

    然后先开始遍历我接下来用(x,y)来代替m[i][j]了。

    按照上面代码遍历顺序。

    当0种物品或者0背包容量时候毫无疑问总价值为0---->所以(0,j)=0并且(i,0)=0


     

    1)当0号物品,和一号物品的情况下

    当物品仅有编号为1号物品的时候,背包容量为1的时候,此时判断当前背包容量是否大于1号物品的体积。

    可以看见一号物品的体积为4,于是维持(i-1,j)也就是(0,1)时候的价值0;

    同理我们一直到背包容量为3的时候,都是小于1号物品的体积的,所以都等于自己(i-1,j)时候包内的价值,所以都是0。

    这样(1,1)(1,2)(1,3)都是0

    当道(1,4)就不一样了这时候1号物品的体积等于了包的容量。这时候我们就想放进去。

    怎么判断放不放呢?我们先给我们的背包腾出4个空间,看看腾出4个体积情况下包的价值是多少。然后把1号物品放进去和之前(0,4)比较下就好了。

    看下公式(i,j)=max((i-1,j),(i-1,j-1号物品的体积)+1号物品的价值);

    这样就简单明了啦,

    i-1的意思就是不算当前物品,或者说是前i-1个物品的情况下。

    j-w[i]的意思就是当前背包容量减去当前物品

    于是(i-1,j-1号物品的体积)+1号物品的价值)就是腾出4个体积后放入物品1后的价值,这个值为一号物品的价值8

    很明显,8>0,所以(1,4)=8

    接下来4-12同样,不过只有物品1所以妥妥的都是8于是(1,4)(1,5)......(1,12)都是8


     

    2)当有0,1,2号物品的情况下

    首先(2,0)=0这没啥毛病

    (2,1)时候,背包容量小于当前2号物品体积,所以=0;(2,1)(2,2)(2,3)都是

    当(2,4)时候有了变化,(2,4)依然小于当前2号物品体积,所以这时候我们用(1,4)时候,(1,4)代表有0和1号物品时候的包内最大价值,我们在上面已经算出来了是8,于是(2,4)=8;

    同理一直到(2,5)还是8.

    但是当(2,6)这时候包已经可以放下2了,我们就给2号物品腾出6个空间把2号物品放进去,腾出6个空间后,现在2还没有放进去于是(1,0)=0,现在把二放进去就是(2,6)+2号物品的价值10

    因为(1,6)=8<10所以(2,6)=10

    同理,(2,7)...(2,9)都是10了

    当(2,10)时候这时候又发送变化了,我们再给2号腾出6个空间发现(1,4)=4居然可以放下了,于是我们再把2号物品一起装到包里。就变成了(2,10)=18;

     

    通过这两个例子应该很清楚了

    下面我打印下结果看下是不是这样:

    看见了把没毛病。确实和我解释的一样,那么下面的也都是这样了,最后要获取最大的价值。直接m[6][12]=24就行了。

    总之最关键的就是那句话

    m[i][j]=max(m[i-1][j],m[i-1][j-w[i]+v[i]])

    但是理解了还不够,最好自己推演一遍,我觉得这是掌握疑难最好的办法。

    就脑子里面想想会漏掉很多细节,推演一遍就可以真正懂。













    种一棵树最好的时间是十年前,其次是现在。
  • 相关阅读:
    python的内存管理
    redis 为啥要主从复制·
    django框架的ORM模型优缺点
    Pytorch学习:实现ResNet34网络
    Pytorch学习:线性回归
    Pytorch学习:CIFAR-10分类
    论文阅读笔记(六十七)【arXiv2021】:Contextual Non-Local Alignment over Full-Scale Representation for Text-Based Person Search
    论文阅读笔记(六十六)【ICCV2019】:Adversarial Representation Learning for Text-to-Image Matching
    论文阅读笔记(六十五)【ECCV2018】:Deep Cross-Modal Projection Learning for Image-Text Matching
    论文阅读笔记(六十四)【arXiv2021】:TransReID: Transformer-based Object Re-Identification
  • 原文地址:https://www.cnblogs.com/islch/p/12567179.html
Copyright © 2011-2022 走看看