zoukankan      html  css  js  c++  java
  • 滚动数组优化

    数组是最常用的数据结构之一,现在我们对数组的下标进行特殊处理,使每一次操作仅保留若干有用信息,新的元素不断循环刷新,看上去数组的空间被滚动地利用,此模型我们称其为滚动数组。其主要达到压缩存储的作用,一般常用在DP类题目中。因为DP题目是一个自下而上的扩展过程,我们常常用到是连续的解,而每次用到的只是解集中的最后几个解,所以以滚动数组形式能大大减少内存开支。

    一、二维滚动数组

    例1:0-1背包问题

    问题描述:

    有 n 件物品x1, x2, …, xn , 每件物品有一个价值和一个重量,分别记为:

           v1,v2, …vn

           w1,w2, …wn

    其中所有的 wi 均为整数。 现有一个背包,其最大载重量为m,要求从这n件物品中任取若干件(这些物品要么被装入要么被留下)。问背包中装入哪些物品可使得所装物品的价值和最大?

    我们很容易得出状态转移方程:f(I,j) = max{f(I-1, j-w[I]) + v[I], f(I-1, j)}

    例如,容量为10,有5个物体,

    重量为3   5  1  9  7

    价值为11 28  6  49 35

    第十三讲 动态规划之滚动数组 - sxyckjzh - 随风飞扬

    从推导过程中可以看出,第I阶段的状态值只与I-1阶段有关,以前的数据保存在那里已经毫无意义。为此,我们就想到了利用滚动数组进行优化。

    具体实现时,我们可以将f数组的空间由[0…n,0..m]改为[0..1,0..m],空间复杂度由O(n*m)下降到O(2*m)。在存储过程中,我们设定一个变量c,则语句段为:

    c:=0;

      for i:=1 to n do begin

        c:=1-c;

        for j:=1 to m do begin

          f[c,j]:=f[c,j-1];

          if j-t[i]>0 then

            if f[1-c,j-t[i]]+p[i]>f[c,j] then f[c,j]:=f[1-c,j-t[i]]+p[i];

        end;

      end;

    这样,二维数组f的第一个下标值的取值就在0,1之间循环变化,实现了数组的滚动存储。

    二、一维滚动数组

    其实,在二维滚动数组的基础上,我们还可以优化为一维滚动数组,但此时滚动的方向尤其重要。例如上例的01背包我们可以降为一维,但在递推f[j]时应按m到0的顺序,这样才能保证推f[j]时f[j-w[i]]保存的是状态f[i-1,j-w[i]]的值。如上表中的第3阶段的数据如下表,在递推第4阶段时,最后状态f[10]的值是由f[10]的值和f[1]+49比较而来,此时,要保证f[1]的值是上一阶段的结果,若方向向反,就很难保证此值不被更新。

    第十三讲 动态规划之滚动数组 - sxyckjzh - 随风飞扬

    相应语句段为:

    for i:=1 to n do

     for j:=m downto 0  do

              if (j>=wi) and (f[j-wi]+pi>f[j]) then

    f[j]:=f[j-wi]+pi;

    这样,新产生的数据将不断覆盖旧数据,实现了一维数据的滚动效果。

    三、MOD滚动数组

    滚动数组应用的条件是基于递推或递归的状态转移中,反复调用当前状态前的几个阶段的若干个状态,而每一次状态转移后,都有固定个数的状态失去作用。

    滚动数组便是充分利用了那些失去作用的状态的空间,填补新的状态。

    Mod 滚动数组主要应用在需要调用多个前面的阶段的状态的情况。

    例2:楼梯有n阶台阶,上楼可以一步上1阶,也可以一步上2阶,编一程序计算共有多少种不同的走法。

    经过分析,此题的状态转移方程为:f[I]=f[I-1]+f[I-2],f[1]=1,f[2]=2

    此时的f[I]只跟f[I-1]和f[I-2]有关,所以用滚动数组可优化空间,但如何实现调用两个前面的阶段的状态情况?就要用到MOD滚动数组。语句段为:

    f[1]:=1;

    f[2]:=2;

    for I:=3 to n do

      f[I mod 3]:=f[(I-1) mod 3]+f[(I-2) mod 3];

    这样,在程序执行过程中只利用了三个空间f[0],f[1]和f[2],实现了数组的滚动效果。

    滚动数组实际是一种节约空间的办法,可根据具体题目要求选择相应的滚动数组进行优化。

  • 相关阅读:
    Chain of Responsibility Pattern
    Visitor Pattern
    Command Pattern
    Mediator Pattern
    Memento Pattern
    Observer Pattern
    State Pattern
    Strategy Pattern
    HTMLTestRunner修改Python3的版本
    loadrunner 检查点
  • 原文地址:https://www.cnblogs.com/Aragaki/p/7516022.html
Copyright © 2011-2022 走看看