zoukankan      html  css  js  c++  java
  • 【动态规划】01背包问题

      今天小编闲的不行,就打开洛谷,随便一打卡就是大吉,还宜刷题。

      正巧上午比赛时有一道背包问题,于是小编默默打开试炼场,瞅准了背包问题(别问我为什么),正所谓自知者明,小编也知道自己很水(建议看背包九讲),于是挑了三道题:

      在写之前总得知道什么是背包问题吧,背包问题一般长这样:

     题目:有N件物品和一个容量为V的背包。第i件物品的费用是w[i],价值是value[i]。求解将哪些物品装入背包可使价值总和最大。

      那么如何解这种题目呢,先定义一个数组f[i][j]为当一共有i件物品,背包容量为j时的最大价值。然后就要找状态转移方程了,小编以前总认为状态转移方程难写,但是只要一项一项列出来就好了。对于每一个物品,无非就两种可能:要么选,要么不选。那么先看选,凡是总有回报和代价把,选了之后代价是什么呢?想一想,是不是选了之后背包剩余容量就减少了;那么回报呢?当然是价值增加了呗。但是不选就不一样了,应为啥也没干,最大价值和之前一样,不增不减。这不就出来了嘛,两种情况如下:

    •   选:f[i][j]=f[i-1][j-w[i]]+value[i];
    •        不选:f[i][j]=f[i-1][j];

      因为题目求的是最大价值,所以两者中取大的就可以了,得到以下状态转移方程:

      f[i][j]=max(f[i-1][j-w[i]]+value[i],f[i-1][j]);

      有没有发现什么,我们用了二维数组,虽然时间上已经难以优化,但是空间上还是可以优化成一维数组的,只要同时去掉i的那一个维度就可以了,因为二维数组有太多不需要一直记录的,直接不断更新一维数组(滚动数组的方式)就可以了,更改如下:

      f[j]=max(f[j-w[i]]+value[i],f[j]);

      具体怎么实现,看几道吧。

      先看第一道:

     

      这道题处于秒杀的行列,直接用刚才的方法,把钱数看成是容量,把重要程度*价格看成是价值就好了,直接写就行,代码奉上:

     1 #include<iostream>
     2 using namespace std;
     3 long long cost[30000],w[30000],f[30000],ans;
     4 int main()
     5 {
     6     long long n,m;
     7     cin>>n>>m;
     8     for(int i=1;i<=m;i++)
     9     cin>>cost[i]>>w[i];
    10     for(int i=1;i<=m;i++)
    11     for(int j=n;j>=cost[i];j--)
    12     {
    13         if(j>=w[i])
    14         f[j]=max(f[j],f[j-cost[i]]+w[i]*cost[i]);
    15     }
    16     cout<<f[n];
    17     return 0;
    18 }

    先来看一下采药,比上面的还简单:

      把时间看成容量,就可以了,代码献上:

     1 #include<iostream>
     2 using namespace std;
     3 int t,m,w[1000],cost[1000],f[1000];
     4 int main()
     5 {
     6     cin>>t>>m;
     7     for(int i=1;i<=m;i++)
     8     cin>>w[i]>>cost[i];
     9     for(int i=1;i<=m;i++)
    10     for(int j=t;j>=w[i];j--)
    11     {
    12         f[j]=max(f[j],f[j-w[i]]+cost[i]);
    13     }
    14     cout<<f[t];
    15     
    16     return 0;
    17 }

    最后来看小A点菜:

      这道题乍一看没思路,还按照刚才的思路:要么吃,要么不吃,吃有什么代价,什么回报呢?钱变少了,方案数变多了呗;不吃呢?还是原来的方案数。这样两种情况就出来了:

    •   f[j-cost[i]];
    •        f[j]

       【注意】情况有变,这一次就不那么简单了,因为选和不选是两种不同的方案数,题目求的是一共的方案数,所以不是max,不是min,而是+。

      归根结底长这样:f[j]=f[j]+f[j-cost[i]];

       这样代码就出来了,代码呈上:

     1 #include<iostream>
     2 using namespace std;
     3 int n,m,cost[100000],f[10000];
     4 int main()
     5 {
     6     cin>>n>>m;
     7     for(int i=1;i<=n;i++)
     8     cin>>cost[i];
     9     f[0]=1;
    10     for(int i=1;i<=n;i++)
    11     for(int j=m;j>=cost[i];j--)
    12     f[j]=f[j]+f[j-cost[i]];
    13     cout<<f[m];
    14     return 0;
    15 }
  • 相关阅读:
    appium自动化测试搭建
    How to install Qt Creator on Ubuntu 18.04
    Luci
    OpenWrt 根文件系统启动过程分析
    shell 杂烩
    OpenWrt Luci 调试日志输出的一种方法
    jQuery实现购物车计算价格的方法
    js实现购物车添加,减少数量
    golang-键盘录入数据
    JAVA存储机制(栈、堆、方法区详解)
  • 原文地址:https://www.cnblogs.com/TFLS-gzr/p/10589576.html
Copyright © 2011-2022 走看看