状压DP
状压DP这玩意儿说实话没什么总结的,不过还是要说说
既然是状压,那么就少不了位运算,所以位运算要熟悉
类 型 |
运算符 |
含义 |
位逻辑 运算符 |
& |
按位与 |
| |
按位或 |
|
^ |
按位异或 |
|
~ |
取反 |
|
移位运 算 符 |
<< |
左移 |
>> |
右移 |
总结起来说,就是先把它写成二进制(8位),然后按下表规则进行运算
类型 |
符号 |
规则 |
例子 |
按位与 |
& |
同1为1,其余为0 |
9 00001001 & 5 00000101 1 00000001 |
按位或 |
| |
同0则0,其余为1 |
| 5 00000101 13 00001101 |
按位异或 |
^ |
不同则1,相同则0 |
^ 5 00000101 12 00001100 |
取反~ |
~ |
0变1,1变0 |
9 00001001 ~ 246 11110110 |
左移 |
<< |
丢掉最右,整体右移 |
>> 2 00000010 |
右移 |
>> |
丢掉最左,整体左移 |
9 00001001 << 2 00100100 |
再说说一些实战中的小技巧把
比如【SCOI2005互不侵犯】一题中,放置一个国王后,它那一行内的左右不能再放,直白点就是每一行不能有相邻两个1出现
当然我们可以枚举每一种情况,然后判断是否有相邻的两个1,但是有时候情况就会很多,如【炮兵阵地POJ1185】,但是可行的情况却不多,所以我们可以先把每一行中可行的找出来
如何找呢?想到dfs没?这可是一个找所有方案的利器啊!
比如当n=4的时候,我们要找出0000,0001,0010,0100,0101,1000,1001,1010这些方案
具体怎么找就不说了,看看代码
void dfs(int x,int s) { if(x==n) { 记录下s return; } dfs(x+1,s<<1); if(!(s&1)) dfs(x+1,(s<<1)+1); } |
主程序调用dfs(0,0)即可
然后就是写代码的一些技巧,动态规划出了可以写递推以外,还可以以记忆化的形式实现,比如说【棋盘游戏】一题(下面有链接),我考试的时候写递推就写昏了,但是改成记忆化,也就是dfs的形式,很轻松就写出来了
我做过的一些状压:
http://blog.csdn.net/jiangzh7/article/details/8592387
http://blog.csdn.net/jiangzh7/article/details/8619644
Mondriaan's Dream POJ2411【基础状压】
http://blog.csdn.net/jiangzh7/article/details/8629641
http://blog.csdn.net/jiangzh7/article/details/8629872
http://blog.csdn.net/jiangzh7/article/details/8631048
http://blog.csdn.net/jiangzh7/article/details/8631768
http://blog.csdn.net/jiangzh7/article/details/8731992