zoukankan      html  css  js  c++  java
  • 【持续更新】dp优化浅谈:理论篇

    一.决策单调性优化:单调队列/斜率/四边形不等式优化

    (1)单调队列与单调队列优化

    当一个人比你小还比你强的时候......

    单调队列是一种严格单调的队列废话,一般支持两个操作:

    1. 插入一个新的元素,该元素从~队尾开始向队首进行搜索,找到合适位置插入,并删除之后的数据
    2. 删除队首元素

    这两个操作是单调队列的基本操作,也是我们之后利用单调队列优化dp的时候dp方程的显著特征

    一个典型的应用是 滑动窗口

    • Problem1. 滑动窗口

    给定 (n) 个整数,求连续 (k) 个数字的和最小是多少。

    网上一大堆题解,这里就不具体讲了qwq
    时间复杂度分析: 由于每个元素入队和出队一次,所以维护队列的均摊时间复杂度为 (O(1))

    单调队列在动态规划的优化中有着广泛的应用,下面我们来看几道例题:

    • Problem2(NOIP 2010) 烽火传递

    烽火台又称烽燧,是重要的军事防御设施,一般建在险要或交通要道上。一旦有敌情发生,白天燃烧柴草,通过浓烟表达信息;夜晚燃烧干柴,以火光传递军情,在某两座城市之间有 (n(n leq 10000)) 个烽火台,每个烽火台发出信号都有一定代价。为了使情报准确地传递,在连续 (m (m leq n))个烽火台中至少要有一个发出信号。请计算总共最少花费多少代价,才能使敌军来袭之时,情报能在这两座城市之间准确传递?

    • Solution2

    考虑dp废话,设 (f_i) 表示点燃第 (i) 个烽火台所需的最小代价,显然有状态转移方程 (f_i=min{ f_j }+a_i,j=i-m,...,i-1) (ans=min(f_{n-m+1},...,f_n))
    暴力转移?时间复杂度 (O(nm)),显然超时
    我们继续观察上面这个式子,维护的是连续 (m) 个数中最小的数,就是我们之前 Problem1 中滑动窗口的形式
    考虑单调队列优化转移,转移复杂度为 (O(1)),时间复杂度下降为 (O(n))

    感觉单调队列优化是不是一般都会讲一下多重背包qwq,那这里也讲一下

    • Problem4. 单调队列优化多重背包

    (n) 种物品,每种物品有对应价值 (w_i) ,对应体积 (v_i) ,对应数量 (K_i) ,给出背包体积 $V,求背包可装下的最大价值。
    期望复杂度 (O(n imes V))

    • Solution3

    首先考虑基础的暴力做法,即把多重背包暴力转化为01背包。
    (f_{i,j}) 表示前 (i) 种物品,剩余背包体积为 (j) 的最大收益,我们的转移方程显然是:
    (f_{i,j}=maxlimits_{k}{f_{i-1,j-k imes v_i}+k imes w_i}),其中 (k) 枚举的是当前物品的数量。
    然后我们如果固定 (i),考虑第二维的状态,而且不考虑别的物品的体积,那么这个方程有个显然的等价形式(下面把第一维压掉了):
    (f_{p imes v_i}=maxlimits_{p-c_i leq k leq p-1}{f_{k imes v_i}+(p-k) imes w_i}),其中 (p) 枚举了到现在一共取了多少个,(k) 枚举的是上一次取了多少个。
    其实如果考虑其他物品的体积,其实也很容易改,而且这就是单调队列优化多重背包的标准方程,其中 (r) 为其他物品的体积和,也可以理解为“余数”

    [f_{p imes v_i + r}=maxlimits_{p-c_i leq k leq p-1}{f_{k imes v_i +r}+(p-k) imes w_i} ]

    我也不知道为什么这个框框突然断了,反正继续
    观察一下这个式子的形式,我们的 (k) 的取值范围会随着 (p) 的增大而刚好增大,而且上下区间同时 (+1) ,而且是在这个区间里找最值
    这是什么?单调队列!
    考虑一个决策 (k),像前面讲的滑动窗口一样,如果它晚一点被考虑到,那么就把他放着
    但是如果有一个决策比他晚而且比他优,那他就没用了,直接出队,维护一个 (k) 单调递减,(f_{k imes v_i +r}-k imes w_i) 单调上升的单调队列。
    (为什么我们要维护 (k) 递减而不是递增呢?因为我们现在是倒序枚举 (k) 来 dp,所以原因跟一维的01背包一样,如果是顺序的话就不用了)
    所以我们接下来对每个 (p) 执行这样子的算法流程:

    1. 检查队头是不是应该在 (k) 现在该在的范围里面,把大于 (p-1) 的决策点出队
    2. 取队头为最优决策,更新 (f_{p imes v_i+r})
    3. 把新决策 (k=p-c_i-1)插入队尾,入队前检查队尾单调性

    整个算法的期望复杂度为 (O(n imes V))

    二.数据结构优化:前缀和/线段树/树状数组优化

    咕了。

    三.其他优化:滚动数组/矩阵乘法/各式各样的推式子优化

    咕了。

  • 相关阅读:
    Javascript 计时事件说明
    结合RibbonControl设计MDI窗体,在子窗体关闭后,顶部显示额外的控制栏残影
    交叉验证[转]
    [转载】我的数据挖掘之路 by wrchow
    《这些道理没有人告诉过你》摘记
    2017BUAA软工第0次作业
    SSM框架+slf4j 以Gradle实现
    RMQ(ST算法)
    博客园装饰
    【转载】UVa 11464 Even Parity 偶数矩阵
  • 原文地址:https://www.cnblogs.com/lgj-lgj/p/13448722.html
Copyright © 2011-2022 走看看