状压DP学习笔记(一)

来源:互联网 发布:软件打开闪退 编辑:程序博客网 时间:2024/06/05 00:40

首先,什么是状压。

所谓状压,就是状态压缩。就是将原来需要很多东西来储存的状态存在一个很小的空间内,并且并不影响动态规划的决策和转移。

最简单的例子就是可以将一个地方是否有东西表示成二进制位中的一位。

很多东西都可以用状态的压缩,有时不仅仅是DP。举个最简单的例子,USACOchecker这道题,就有一种方法就是用二进制位来确定无法放置的位置,实际上本质就是一种状态的压缩。

看到一道很恶搞的题目。题目看起来很吓人,是说m*n的棋盘上放k个棋子,使之相互之间不相邻。(M<=80,n<=80,M*n<=80),如果说这个题数据范围没有给最后一个,那这个题肯定是没有办法来做的。但是有了最后一个条件,那么这个题就可以发现这样一件事,就是它的行和列之间较小的那个,最坏的情况也仅仅只有9而已。所以可以使用状压来做。

那么如何来实现呢?他跟某位神牛写的状压教程中的引子,也就是MN棋盘上放车还不一样,因为他的影响范围是四个方向。那么首先,不考虑其他的因素的话,我们首先DFS出对于一行来说,所有可行的方案,所有的一行上的状态必须满足属于这个集合,否则它肯定不是一个可行的解。然后考虑上一行的情况,因为只有上一行的东西才有可能影响到这一行的决策。那么我们就可以这么做了,设状态(i,j,k)表示当前已经处理到第i行,然后第i行的状态为j,前i行已经放下了k个棋子。那么就很容易得出转移的方法,那就是枚举ij,再枚举前一行的状态,如果不冲突,那么就将其累加进当前状态。边界状态就是f[0,1,0]:=1(假设我们生成数组第一个就是什么也不放)

那么如果说这个题,再改一改,从四方向不相邻变成八方向不相邻呢~这个题就是sguLittleKings这个题。基本跟上一个题一样,就是我们判断不用上下两个状态&了,变成我开一个冲突数组op[i],表示与第i中状态冲突的基本状态,换句话说,现在变成只要别的状态与这个opi]&为0的话,就是可以放的。

接下来说一说炮兵阵地这个题,这个题因为听wmh说过,所以我有那么一点印象,就是说影响范围从一行变成两行,那么就是要考虑前两行的情况。这个题因为k不固定,所以状态减小一维,但是因为要多考虑一行,所以状态又要加一维。f[i,j,k]表示第i行决策为j,第i-1行决策为k能得到的最多的安放炮兵数量。然后转移就是f[i,j,k]:=max(f[i-1,k,p]+c[j])j,k,p不冲突的情况下。

以上的几个例子,就是状压DP的一个经典的模型,就是棋盘模型。其本质就是有个棋盘,在上面放棋子,然后问方案数一类的问题。

 

原创粉丝点击