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))

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

    咕了。

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

    咕了。

  • 相关阅读:
    CSS3 target伪类简介
    不用position,让div垂直居中
    css3 在线编辑工具 连兼容都写好了
    a标签伪类的顺序
    oncopy和onpaste
    【leetcode】1523. Count Odd Numbers in an Interval Range
    【leetcode】1518. Water Bottles
    【leetcode】1514. Path with Maximum Probability
    【leetcode】1513. Number of Substrings With Only 1s
    【leetcode】1512. Number of Good Pairs
  • 原文地址:https://www.cnblogs.com/lgj-lgj/p/13448722.html
Copyright © 2011-2022 走看看