zoukankan      html  css  js  c++  java
  • [DP之多重背包优化方法]

    首先我们看一道有趣的题目

    然后这道题很快想到是一个多重背包和无限背包混合体

    那么我们就以这道题 来讨论一下多重背包的优化

    首先我们看看朴素打法

    memset(F,63,sizeof(F)); F[0]=0;
      for(int i=1;i<=N;i++)
         for(int k=0;k<=C[i];k++)
           for(int j=T*2;j>=0;j--)
              if(j-V[i]>=0) F[j]=min(F[j],F[j-V[i]]+1);

    很简单 很好懂 但是这样做导致时间复杂度为O(N*C*T) 这道题来看超时到爆炸

    那么我们考虑两种方法 第一种是像wph写的 首先贪心一会儿 然后再背包 答案大概在T到2*T的范围内

    但是这种方法导致代码很玄学 因为贪心的时候很有可能有一些东西处理不到

    那么我们考虑第二种方法 就是优化多重背包 因为无限背包的时间是足够的

    优化多重背包有两种算法,但是下面只介绍最快的:

    1.用二进制优化 这个好像我有写过 但不知道怎么打和原理了 陈年老事 具体可以问wph 时间复杂度O(NTlog(C))

    2.可以用单调队列进行优化 时间复杂度为O(NT)

    我只讨论单调队列优化 我们先列出有

    F[i][j]=min(F[i-1][j-vi*k]+k) (0<=k<=ci)

    那么我们发现 每一次都是和vi有关的 我们其实可以把式子变一下

    令a=j/v[i] b=j%v[i] j=a*v[i]+b

    F[j]=min(F[b+k*v[i]]-k)+a (a-c[i]<=k<=a)

    我们把k枚举 就是单调队列了,具体看下面

    其实我们在做j这个状态的时候 k和a是相同的 当然方便理解 因为以前的是k 现在的是a 只是对于当前来说我的a和k是一样 但是对于别的来说 我就要找最小的k

    我们可以枚举b 然后可以每次都 +v[i] 处理  这样的话每一次每个位置只会被扫1遍 大大减少了时间  所以时间复杂度为O(NT)很显然

    memset(F,63,sizeof(F)); F[0]=0;
      for(int i=1;i<=N;i++)
      {
        for(int j=0;j<=50000;j++) G[j]=F[j];
        
        for(int b=0;b<V[i];b++)
        {
          head=1; tail=0;
          for(int j=b;j<=50000;j+=V[i])
          {
            int a=j/V[i];
            while(head<=tail&&Q[head].first<a-C[i]) head++;
            if(head<=tail) F[j]=min(G[j],Q[head].second+a);
            while(head<=tail&&Q[tail].second>=G[j]-a) tail--;
            Q[++tail]=make_pair(a,G[j]-a);
            
          }
        }
      }

    良心的贴一道这道例题的链接 这里

  • 相关阅读:
    oracle登陆认证方式
    oracle用户管理
    oracle sqlplus常用命令
    瀑布开发模式和敏捷开发模式
    在C#中用RX库和await来实现直观的状态机
    C#实现简单的字符串加密
    双屏办公之体会
    利用json2csharp快速生成C#类
    .Net中的插件框架Managed Extensibility Framework
    解决NVidia显卡最大化和最小化窗口时的卡顿问题
  • 原文地址:https://www.cnblogs.com/wohenshuai/p/5943557.html
Copyright © 2011-2022 走看看