状态压缩和倍增优化dp
本章主要讨论通过 优化状态设计 优化
\text{0x56} 状态压缩 \text{dp}
在某些题目中,我们需要用一整个大小为
n 的集合S 描述「状态」,但如果该集合中的每个元素都是不超过k 的自然数,那么我们就可以考虑将这个集合看作一个n 维k 进制数,并使用一个整数i\in[0,k^n) 描述这一维状态。像这样将集合转化为整数并作为\text{dp} 的一维状态的状态设计方法,称为 状态压缩,简称状压。
- 最短Hamilton路径
\text{ / } 旅行商问题\text{ / } 吃奶酪
最经典的状压题型之一——最短Hamilton路径问题。使用一个
f(i,j)=\min\limits_{k\in[0,n)}\Big\{f(i\oplus\!(1\!\ll\! j),\, k)+\operatorname{dis}(k,j)\Big\}
- 棋盘覆盖
\text{ / } Corn Fields\text{ / } 炮兵阵地
也是很经典的一类状压题型——方格填充问题。并且填充的图形仅与相邻的若干行有关,因此容易按照行号划分阶段并使用状态压缩表示各行状态,进而使用动态规划算法。一个值得注意的技巧是,可以 先根据题意的限制,预处理出所有合法的状态,以避免
- 宝藏
这是一个较为复杂的状压
但是刚开始看到这道题的时候,会感觉更像是一道搜索。已开凿的道路可以任意同行并不花费代价,因此题目所求就是让所有宝藏屋连通的最小代价。于是可以先考虑写下搜索算法:
- 任选一个节点为根,即为赞助商帮忙打通的宝藏屋 ;
- 任选一个已经打通了的宝藏屋,从它开凿一条可开发的并通往任意一个未打通的宝藏屋的道路,累加答案,然后重复这一步骤,直到宝藏屋被全部打通,更新答案。
如果在每次递归过程中都重复扫描所有已打通的宝藏屋,并尝试打通一条道路,显然会遍历相当多重复的状态,时间复杂度会相当高。为此可以做出两点限制(可视作剪枝操作):
- 【优化搜索顺序剪枝】先打通浅的宝藏屋,再打通深的宝藏屋。显然这不会对最终答案造成影响。
- 【最优化剪枝】对于多个同一种已打通的宝藏屋的集合,只需要关心其中代价最小的那个。因为打通后续的宝藏屋所需的代价与当前已打通的宝藏屋的集合内部的连接方式无关。
但是进一步分析可以发现,第一点限制其实体现了动态规划的「阶段」,而第二点限制事实上确立了动态规划的「最优子结构」,而
f(i,j)=\min\limits_{\operatorname{valid}(k,j)}\Big\{f(i-1,k)+(i\!-\!1)\times\operatorname{cost}(k,j)\Big\}
其中 但事实上这才是本题最大的难点之一。
本题其实给了我们很多启示:首先,关于
- Bill的挑战
这是一道稍有难度的状压 除了数据范围几乎没有任何提示(大雾。突破口在于对
\text{0x57} 倍增优化 \text{dp}
倍增优化 是一种巧妙的优化思路,它将原本复杂度为
\mathcal{O}(n) 的线性递推通过预处理转化为复杂度为\mathcal{O}(\log n) 的成倍增长式递推,个人认为与矩阵加速递推有异曲同工之妙,很多时候无法使用,也因此很难考虑到;但是一旦在适用范围内使用,就可以达到一些超乎寻常的优化效果。
- 跑路
这个题作为倍增思想的一个引入。
首先我们肯定不能先求最短路再尝试二进制拆分,因为可能会有一条稍长的但是长度正好为
- 开车旅行
这是一道很经典 麻烦 的题目,关键在于预处理。