狀態壓縮動態規劃(簡稱狀壓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個國王有幾種方法,剩下的就和上一個例題差很少了