落地:SMAWK 加速一维分段 DP
行最小值:Monge 与 SMAWK 把 SMAWK 当作一个独立的矩阵搜索算法讲完,留下的问题是 DP 里哪来那么多现成的 Monge 矩阵。本页给出一个完整的落地案例,取自 Erickson 附录 D 的习题 5 与习题 6 [1]:把一列排序的数切成 个连续箱,最小化各箱跨度的平方和。这个代价满足 Monge 条件,分段 DP 的每一层递推化成一次行最小值,总时间从 降到 。
1 · 从分箱到一维分段 DP
考试成绩、接口延迟采样这类一维数据,常用直方图压成一眼能读的摘要。变宽直方图(variable-width histogram)不要求箱等宽,箱界可以任选,「箱界放哪」于是成了优化问题:Erickson 附录 D 的习题 6 用它总结全校学生的绩点 [1]。本页取姊妹题(习题 5)的纯几何代价,称 k 区间覆盖(k-interval cover):给定排序互异的 与正整数 ,选 个区间盖住全部点,最小化区间长度的平方和。平方专罚悬殊,最优的 个区间会长短相近;习题 6 的箱代价还要乘上箱内点数,同属一维分段,本页不展开。
工程里现成的两种分法都不碰优化。等宽分箱(equal-width)把值域 均分成 段,密集区与稀疏区一视同仁,还可能产出一个点也没有的空箱;等频分箱(equal-frequency)给每箱约 个点,箱内点数齐了,跨度却听天由命。最优解得回到结构上:最优的 个区间必然把点列按下标切成 个连续组,一组从第 点延伸到第 点时,最短的覆盖区间就是 ,代价
问题至此变成枚举最后一段:相册排版与内容分栏里的一维分段 DP:同一套「枚举最后一段」递推,段代价换成 ,聚合取和。朴素实现里每层的每个终点都要扫一遍全部起点, 层合计 。
2 · 组代价的 Monge 性
继承了平方函数的凸性,这份凸性落到矩阵语言里就是 Monge 条件。
定理 2.1 排序互异的点列上, 满足四边形不等式:对一切 与 ,。
证明 Monge 性等价于全部相邻 子阵满足不等式,只需验证 、 的情形。记 、、,点列互异保证 。左边为 ,右边为 ,右边减左边恒等于 ,与 的符号无关。∎
这条不等式还有一个不看代数的读法。四个下标给出两种配对方式:交错配对取区间
与
,嵌套配对取
与
。两种配对的总长度相同,嵌套的一对一长一短,交错的一对更均匀,凸的代价函数罚的就是悬殊,嵌套配对更贵。引擎侧的核对同样只查相邻
:costMatrix 把
铺成显式矩阵,isMonge 在预设与随机点列上逐格验证,测试把这一性质锁死。
3 · 每层递推与隐式矩阵
记 为「前 个点(下标 到 )切成 箱」的最优代价。最后一箱含下标 到 ,前 个点交给上一层:
固定层号 ,右边就是矩阵 的第 行最小值:一整层递推等于一次「求全部行最小值」。 由 Monge 的 加上一项只随列号变化的 平移而来,四边形不等式两边同增同减,Monge 性原样保留。
真正接上 SMAWK 之前还有两道坎。其一是非法格子:
时「最后一箱」一个点也分不到,dpSmawk 给这些格子补
。它们聚成矩阵的右上三角,这片区域向上、向右封闭,四边形不等式的四项里总是右上角那一项最先变成
,左边一旦出现
右边必然同为
,不等式从不被破坏。其二是矩阵从未被建出:显式铺一张
的表本身就要
时间,优化直接归零。dpSmawk 传给 smawkRowMinima 的只是一个 lookup 函数,SMAWK 要哪格就现算哪格,每格
;Erickson 在 D.7 节用同一手法把平面二部图上的 Bellman–Ford 压到
,并特意强调矩阵从未被显式构造 [1]。
每层 次 lookup 找出全部行最小值 [2], 层合计 ,对照朴素的 ——这正是习题 5(c) 索要的复杂度 [1]。
4 · 对照实验与工作量账本
预设取 24 个成绩样本,分布在 3 到 99 之间,其中有两道宽 13 分的缝(31 到 44、70 到 83)。 时三档答案分开得干脆:等宽分箱总代价 1402,等频 2124,DP 最优 1222,与暴力枚举全部切法的 oracle 一致(测试锁死)。等频输得最多,它只数点数不看跨度,两个中段箱各自横跨 29 分;DP 把两道缝都用作箱界,缝的宽度一分也不计入任何箱。等宽这次运气不差,四箱都非空,但它的箱界钉死在值域的四等分点上,只撞上了两道缝中的一道,数据一换就可能冒出空箱。
工作量的口径预先对齐:dpPlain 计内层
对的求值次数,dpSmawk 计 lookup 调用次数,两者都含首层 24 次前缀代价求值。同一份预设上朴素 784 次、SMAWK 578 次,而两档引擎给出的最优代价与全部逐层数值逐位一致(测试断言)。
dpPlain 与 dpSmawk 的求值次数。
5 · 收益的边界
SMAWK 砍的只是层内。
的每一格都以整层
为输入,层与层之间是硬依赖,
里的
一步也省不掉。层内的收益也没有渐近分析暗示的那么快兑现:写本页之前的预期是「一边平方一边线性,预设上该是碾压」,实测 24 点只从 784 砍到 578,省约 26%。追进 smawkRowMinima 才看清缘由:它不做记忆化,Reduce 阶段与偶数位行的插值会对同一格反复求值,预设与均匀点列上实测每行 8 到 10 次 lookup,
里的常数在
时吃掉了大半收益。点列拉到 60 个(0 到 177 间隔 3),差距才拉开到 3.1 倍(5194 对 1682)。两组数字都原样给出,只报 60 点那一组,对常数的判断就会失真。
适用范围也有一条边界。本页的问题逐层分明,第 层只读第 层,一层算完再开下一层,SMAWK 的离线形态直接可用。同族的更大分段问题未必如此:枚举最后一段:相册排版与内容分栏里的相册 justified 排版与 Knuth–Plass 断行不限段数,单层递推里 依赖同层更早的 ,矩阵的列值边算边生,离线的 SMAWK 接不上,要换 Larmore–Schieber 的在线变体 [3]。
6 · 参考文献
- Erickson, J. (2019). Algorithms (1st ed.). Self-published, appendix D: Advanced dynamic programming, §D.7 & exercises 5–6. http://algorithms.wtf
- Aggarwal, A., Klawe, M. M., Moran, S., Shor, P., & Wilber, R. (1987). Geometric applications of a matrix-searching algorithm. Algorithmica, 2(1), 195–208.
- Larmore, L. L., & Schieber, B. (1991). On-line dynamic programming with applications to the prediction of RNA secondary structure. Journal of Algorithms, 12(3), 490–515.