• 背包问题


    背包问题是一种动态规划问题

    问题是给你背包容量和物品的花费、价值,不一定要将背包装满,问怎样装才可以使价值最大

    背包问题可分为01,完全,多重,混合,分组(互斥),二维费用,依赖

    一:01背包:

    !!!每个物品只有一件,而且v的列举需要倒序

    将n物品放入容量为v的背包,每件物品花费w、价值c都已给出。

    每个物品只有一件,可以选择放或者不放

    用f[j]表示物品放入j的容量时可获得的最大价值

    f[j]=max(f[j],f[j-w[i]]+c[i])//放或者不放的情况比较

    有个大大的注意点:第二层循环体积时应该从v-0!!

    为什么?我们画个图来解决

    横行是物品,纵列是容量

    w[i]      j-w[i]       j          v

           
    E D C F
      B A  
           

     

    这是一个一维数组

    根据状态转移方程

    若-->更新,在更新A时,来源于B或者C,B是这一轮更新的值,C是上一轮更新的值,反正就是不能保证A是由上一个状态得到。

    若<--更新,在更新A时,来源于B或者C,B由于还没有被更新,所以相当于B=D,也就是B还是上一轮的值,那就保证了A是由上一个状态得到。

    初始条件:
    不一定装满的初始状态:f[0-v]=0(要求最大值,初始化最小)
    恰好装满的初始状态:f[0]=0,f[1~v]=-∞(状态不合法,0件物品无法恰好装满任意非0容量)
    1     for(int i=1;i<=n;i++){
    2         for(int j=v;j>=w[i];j--){
    3              f[j]=max(f[j],f[j-w[i]]+c[i]);
    4         }
    5     }

    二.完全背包:

    大致和01背包一样,不同点在于每件物品有无限件

    第二层循环要顺序0-v

    为啥子?咱又来画个图

    w[i]       j-w[i]     j           v

           
    E D C F
      B A  
           

     
     
     
    更新A时,要么从C点,要么从D或B点更新是吧,
    状态转移方程是:f[j]=max(f[j],f[j-w[i]]+c[i])//放或者不放的情况比较
    就是即使是从B点更新过来也无所谓了,因为你物品有无限个嘛!
    初始条件:f[0]=0;
    1 for(int i=1;i<=n;i++){
    2         for(int j=w[i];j<=v;j++){//重量是必须大于这个物品重量的 
    3              f[j]=max(f[j],f[j-w[i]]+c[i]);
    4         }
    5     }

    三.多重背包:

    大致和01一样,只是每种物品取的数量有限

    转化为01背包即可:把一个物品里的取n件物品看成,取若干件不同的物品

    若干件?总不能把他看成n件吧!那这个数据量好大哦。

    其实可以应用二进制,就是说:

    13=1+2+4+6

    这4个数字可以构成1-13中每个数字,所以问题也没有太复杂,而且还转化成功了

     1     //比如 13=1+2+4+6
     2     //nu是最多取几件
     3         t=1;
     4         while(nu>=t){
     5             w[++n]=pr*t;//这一堆组成有几个物品 
     6                                   //这个物品的花费和价值要乘几
     7                                   //相当于捆绑销售
     8             c[n]=va*t;
     9             nu-=t;
    10             t=t*2;
    11         }
    12         //13中的6是在这里分 
    13         if(nu!=0){
    14             w[++n]=pr*nu;
    15             c[n]=va*nu; 
    16         }                 

    四.混合背包

    01+完全+多重

    分类讨论即可

    第二层for循环时,完全是0-v,01+多重是v-0

    所以第二层循环时分类讨论就好

    就加一个check数组判断他是01多重还是完全

    1  for(int i=1;i<=n;i++){
    2         if(check[i]==0) for(int j=w[i];j<=v;j++){
    3                             f[j]=max(f[j],f[j-w[i]]+c[i]);
    4                         }
    5         else            for(int j=v;j>=w[i];j--){
    6                             f[j]=max(f[j],f[j-w[i]]+c[i]);
    7                         }
    8     }

    五.分组背包

    物品被划分为若干组,每一组内物品互斥,最多选一件

    最内层加一个循环,循环的是这个组内的物品

    在最内层加可以保证一个组内只取一件物品

    1 for(int i=1;i<=t;i++){//组数 
    2         for(int j=v;j>=0;j--){//容量 
    3             for(int k=1;k<=a[i][0];k++){//a[i][0]表示这个组内的物品个数
    4                 if(j>=w[a[i][k]]){//容量肯定要大于这个物品才行
    5                     f[j]=max(f[j],f[j-w[a[i][k]]]+c[a[i][k]]);
    6                 }   
    7             } 
    8         }
    9     }

    六.二维费用的背包问题

    每件物品不止一个花费

    就像修房子需要花费人力和财力

    那两个花费的最大值就是两个背包容量

    类比前面,花费是v时有一层循环(不算循环物品个数/组数),dp数组为一维。

    那两个花费就有两层循环,dp数组为二维

    有时候物品总个数也是个限制,这个是隐含条件,也算作一个背包容量,每件物品个数费用为1

    无愧于心,不困于情。
  • 相关阅读:
    分布式事务
    K8s应用案例介绍——阿里云
    数据库索引的底层原理——b树
    Understanding the GitHub flow
    Code Review
    详解微服务架构
    yarn之package.json
    yarn.lock文件
    Git Api——git开发
    Unit Test —— xUnit.net
  • 原文地址:https://www.cnblogs.com/SUMMER20020929/p/9764216.html
Copyright © 2020-2023  润新知