【持续更新】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 \times V)\)

  • Solution3

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

\[f_{p \times v_i + r}=\max\limits_{p-c_i \leq k \leq p-1}\{f_{k \times v_i +r}+(p-k) \times w_i\} \]

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

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

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

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

咕了。

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

咕了。

posted @ 2020-08-06 20:20  L_G_J  阅读(175)  评论(0编辑  收藏  举报