厕所装修的电钻响了一天(阴乐)
目录
状压dp
状态压缩
将一些0/1状态或更复杂的状态压缩成一个二进制数,用于降低时间或空间复杂度的方法
状压dp
利用压缩的状态进行转移的动态规划
实际问题中,状态压缩仅作为一种手段和工具,而如何设计合适的状态和快速的转移方程则是解决状压dp问题的难点和关键,需要因题而异
由于一般情况下状压dp的复杂度为指数级别,因此适用于解决数据范围较小的问题
洛⾕ P1879 [USACO06NOV]⽟⽶⽥Corn Fields
⼀个n*m(n, m <= 12)的矩阵中,有些格⼦不能放棋⼦,任意两个 棋⼦不能相邻(四连通),求有多少种放棋⼦的⽅案?(⼀个也不放也算⼀种⽅案)
- 状压思想:将第k列的棋子状态与S中第k个二进制位一一对应。
- 考虑从上到下一行一行放置棋子,容易发现,一个摆放方案对后续的影响仅跟它用了几个棋子和它最后一行的放置状态有关,因此不难设计出这样的 dp:f[i][S]代表放到第 i 行,第 i 行的放置状态为 S 的方案数。
- 其中 S 是一个 n 位二进制数,第 i 位是 0/1 代表第 i 位放/不放国王。
- 枚举下一行的状态 T 进行转移。
- 如何判断一个转移是否合法。
- 首先 T 自身必须合法,即 T 中的国王不能相邻,用位运算表示即T&(T>>1)=0其次,S到T的转移必须合法,即S&T=0,复杂度
- 事实上,合法的转移远比4𝑛4^n要少
- 可以预处理出所有合法的状态和转移
洛⾕ P2831 [NOIP2016] 愤怒的⼩鸟
平⾯直⻆坐标系的第⼀象限中有n头猪(n <= 18),每头猪是⼀个点,每次从原点发射⼀只鸟,飞⾏轨迹是⼀条抛物线 y = ax^2 + bx (a < 0),在抛物线上的猪可以被消灭。问最少发射多少⻦可以消灭所有点?多组数据,T<=15。
- ⽤⼆进制数表示猪的消灭情况。 三点可以确定⼀条抛物线,已有原点⼀个点,再加上两头猪即可确定抛物线。 预处理g[i][j] = ⼀个⼆进制数,表示过原点、猪i、猪j的抛物线能消灭哪些猪。
- 已求出dp[k](k为⼆进制数,表示已消灭的猪),可以枚举i、j进⾏转移:
- 复杂度
- n = 18 时,
= 84934656,再乘上T = 15,冒了!
- 如何优化掉⼀个n?
- 其实不⽤枚举i、j,因为消灭猪的先后顺序没有影响,只需取状态k中第⼀头还活着的猪即可。
数位dp
数位DP⽤来解决“区间[1, n]中满⾜xx条件的数有多少”的问题,经常是⽤记忆化DFS实现的。
DFS⾥⼀般包括以下参数:
- 当前DFS到第⼏位
- 前⾯出没出现前导0
- 前⼏位是否紧贴着上界
- 关于其他条件的参数