状态压缩DP专题
作者:互联网
状态压缩动态规划(简称状压\(dp\))是另一类非常典型的动态规划,通常使用在\(NP\)问题的小规模求解中,虽然是指数级别的复杂度,但速度比搜索快,其思想非常值得借鉴。
一、位运算相关知识
为了更好的理解状压\(dp\),首先介绍位运算相关的知识。
1.&符号,\(x\&y\),会将两个十进制数在二进制下进行与运算,然后返回其十进制下的值。例如\(3(11)\) & \(2(10)=2(10)\)。
2.|符号,\(x\)|\(y\),会将两个十进制数在二进制下进行或运算,然后返回其十进制下的值。例如\(3(11)\) | \(2(10)=3(11)\)。
3.\(\wedge\)符号,\(x\)^\(y\),会将两个十进制数在二进制下进行异或运算,然后返回其十进制下的值。例如\(3(11)\) ^ \(2(10)=1(01)\)。
4.<<符号,左移操作,\(x<<2\),将\(x\)在二进制下的每一位向左移动两位,最右边用\(0\)填充,\(x<<2\)相当于让\(x\)乘以\(4\)。相应的,’\(>>\)’是右移操作,\(x>>1\)相当于给\(x/2\),去掉\(x\)二进制下的最有一位。
这四种运算在状压\(dp\)中有着广泛的应用,常见的应用如下:
1.判断一个数字x
二进制下第i
位是不是等于1
。
if(((1<<(i-1))&x)> 0){
}
将\(1\)左移\(i-1\)位,相当于制造了一个只有第\(i\)位上是\(1\),其他位上都是\(0\)的二进制数。然后与\(x\)做与运算,如果结果>\(0\),说明\(x\)第\(i\)位上是\(1\),反之则是\(0\)。
2.将一个数字x
二进制下第i
位更改成1
。
x = x | (1<<(i-1))
3.把一个数字二进制下最靠右的第一个1
去掉。
x=x & (x-1)
二、例题讲解
位运算在状压\(dp\)中用途十分广泛,请看下面的例题。
【例1】有一个\(N*M\)(\(N<=5,M<=1000\))的棋盘,现在有\(1*2\)及\(2*1\)的小木块无数个,要盖满整个棋盘,有多少种方式?答案需要\(mod\) \(1,000,000,007\)。
例如:对于一个\(2*2\)的棋盘,有两种方法,一种是使用\(2\)个\(1*2\)的,一种是使用\(2\)个\(2*1\)的。
【算法分析】
在这道题目中,\(N\)和\(M\)的范围本应该是一样的,但实际上,\(N\)和\(M\)的范围却差别甚远,对于这种题目,首先应该想到的就是,正确算法与这两个范围有关!\(N\)的范围特别小,因此可以考虑使用状态压缩动态规划的思想,请看下面的图:
假设第一列已经填满,则第二列的摆设方式,只与第一列对第二列的影响有关。同理,第三列的摆设方式也只与第二列对它的影响有关。那么,使用一个长度为\(N\)的二进制数\(state\)来表示这个影响,例如:\(4(00100)\)就表示了图上第二列的状态。
因此,本题的状态可以这样表示:
dp[i][state]表示该填充第i列,第i-1列对它的影响是state的时候的方法数。i<=M,0<=state<2N
对于每一列,情况数也有很多,但由于N很小,所以可以采取搜索的办法去处理。对于每一列,搜索所有可能的放木块的情况,并记录它对下一列的影响,之后更新状态。状态转移方程如下:
dp[i][state]=∑dp[i-1][pre]每一个pre可以通过填放成为state
对于每一列的深度优先搜索,写法如下:
标签:专题,运算,二进制,压缩,第二列,state,DP,十进制,dp 来源: https://www.cnblogs.com/littlehb/p/15464421.html