状态压缩动态规划(简称状压DP)是很是典型的一类DP。他是利用二进制来描述状态的一种DP方式,你们都知道,DP是解决多阶段决策最优化问题的思想方法,可是有时候阶段多了,维度多了,数组也就爆了,由于虽然维度多,可是有些空间可能用不到,这就很浪费了,(主要是维度多了处理麻烦很恶心)因此咱们就把咱们就把一组数据压到一个int变量里面(只要是整形,什么都好啦)数组
举个生动形象的例子,在01背包中,n个物品的选择方式,就能够用二进制数来表示:1 0 1 1 0(n=5),从低位开始,表示1不选,2选,3选,4不选,5选。优化
既然它与二进制有关,因此咱们就须要讲一讲二进制啦spa
名称code |
做用blog |
举例get |
左移(<<) | 位左移运算将整个数按位左移若干位,左移后空出的部分0。 | 5(101)<<2=20(10100) |
右移(>>) | 位右移运算将整个数按位右移若干位,右移后空出的部分填0。 | 5(101)>>2=1(1) |
按位与(&) | 会将两个十进制数在二进制下进行与运算,而后返回其十进制下的值。在某一位上,只有两个数都是1才返回1 | 5(101)&2(10)=0 |
按位或(|) | 会将两个十进制数在二进制下进行或运算,而后返回其十进制下的值。在某一位上,只要有一个数是1就返回1 | 5(101)|2(10)=7(111) |
按位异或(^) | 会将两个十进制数在二进制下进行异或运算,而后返回其十进制下的值。在某一位上,只有两个数相同才返回1 | 5(101)^2(10)=0 |
按位非(~) | 把0变成1,1变成0,而后返回其十进制下的值。 | 咳咳,最好不要轻易用,由于int有32位(二进制),前面的所有会变成1 |
检查第i位是不是 1it
if(1<<(i-1)&x)...
检查第i位是不是 0io
if(1<<(i-1)&x==0)...
统计x中有多少个 1table
while(x) { cnt += x&1; x >>= 1; }
检查x中是否有相邻的 1ast
if(x&(x<<1))...
计算x最低位1表明的值
int lowbit(int x) { return x&(-x); }
把第i位变成 1
x |= (1<<(i-1))
把第i位变成 0
x &= ~(1<<(i-1))
把第i位取反
x ^= (1<<(i-1)
末i位取反
x^(1<<(i-1))
x包含y
if(x&y==y)... OR if(x|y==x)...
取右边连续的1
(x^(x+1))>>1
把右边连续的0变成1
x&(x-1)
把右边连续的1变成0
x|(x+1)
把右边第一个0变成1
x|(x+1)
这是一道典型的状压DP(废话,学的状压不给状压给什么)
咱们用一个M数组来存储每一行的状况(土地是否贫瘠),而后用state数组表示某一种种植方法是否能够知足任意两个种植物不相邻,(bool数组)。
而后开始一行一行的枚举状态,若是可用而且没有贫瘠土地,就枚举上一排的,看不相邻的状况就转移,最后把最后一行全部的状况累计起来便可。
仍是和玉米田差很少的操做,可是dp数组须要加一维,因此就成了在某一行的某种状态中已经放了x个国王有几种方法,剩下的就和上一个例题差很少了