狀壓這個和二進位制分不開關係
所以,對於二進位制的熟悉是必不可少的技能
& 與操作,1不變,0變0
| 或操作,0不變,1變1
^ 異或操作,0不變,1取反
~ 取反操作,把每乙個二進位制位0變1,1變0
還有一些複雜操作可以根據這些去理解
狀態壓縮
所謂狀態壓縮就是把dp的每一次轉移時的狀態用二進位制來表示
或者用二進位制來間接表示
比如這裡有10個蘋果,編號1-10
我拿走了1,4,7,9這四個蘋果
那麼我們可以用011011010這一串二進位制數來表示現在的狀態
0表示這個位置沒有蘋果,1表示有
那麼這就是乙個狀態
相比拿乙個bool型的陣列,這樣表示更方便,記憶體更小,操作更簡單
現在我想把拿走的蘋果放回去,沒拿走的拿走
那麼狀態就變成100100101
直接取反 a=011011010 b=100100101
a==~b;
這時候就充分展示了狀態壓縮的快捷性
下面我們講一道例題。。。。。
在n*n(n≤20)的方格中放置n個車,每個車可以攻擊所在的行和列,求方案總數
直接上排列組合,n!,很好理解啊
在n*n(n≤20)的方格棋盤上放置n 個車,某些格仔不能放,求使它們不能互相攻擊的方案總數。
這時候一些格仔不能放,就要考慮每一行的情況
但是 ,,,,即使每一行中有的格仔不能放,最終還是每一行每一列都要有乙個車子
所以我們用s這個int型的數來表示現在的狀態(行狀態)
如果這一列現在有車子,那這一位就是1
所以最終s一定會變成11111111111(全是1)只有這樣才能把n個車全部放進去
這樣這一狀態有幾個車子說明這就是第幾行
那這樣轉移方程就有了
dp[s]+=dp[s^(s&-s)];
for(;j>0;j-=(j&-j))還有個問題,有些格仔不能放車
這怎麼辦???????????
還記得前面的蘋果嗎
用1表示這裡能放車子,0表示不可以
在狀態轉移的時候&一下就可以啦
j=i&s[num];**如下
#include#define ll long longusing namespace std;
int n,m;
long long dp[1<<20];
int s[25];
int main()
j=i&s[num];
for(;j>0;j-=(j&-j))
} printf("%lld",dp[(1這樣基本的狀壓dp就結束了
也許你已經發現了
所有的n都小於等於20
因為int只有32位
這也是狀壓的前提
所以當你一直為空間時間複雜度著急時
就去考慮狀壓
而狀壓前先找到可以狀壓的數
就是32位以內的
狀態壓縮動態規劃(狀壓DP)
狀態壓縮動態規劃就是我們常說的狀壓dp,前兩天某廠實習生二面面試官隨手就給我抽了一道狀壓dp的題,我根本沒思路,sorry就寫了一行注釋。然後leetcode周賽最後一題又碰到了狀壓dp的題目,我一定要搞定這個型別的問題。加油加油 狀壓dp說簡單也簡單,基本上就是用一串二進位制樹來表示當前情況 的狀...
狀壓DP初探 總結
2018過農曆新年這幾天,學了一下狀態壓縮動態規劃,現在先總結一下。狀態壓縮其實是一種並沒有改變dp本質的優化方法,階段還是要照分,狀態還是老樣子,決策依舊要做,轉移方程還是得列,最優還是最優,無後還是無後,所以它比較好理解。狀壓,顧名思義就是要將一些狀壓想辦法壓縮起來 可以壓,也可以刪 其中這些狀...
狀壓DP的總結
狀壓dp的標誌 資料小 通過題目所給出的條件以後得到的特徵集合小 一 cf259div2 d 題目大意 保證b i 中每個數互質,給出a i 然後求1 n的abs a i b i 最小。a i 30 思路 首先得到b i 必然小於60。這個很重要,因為我們列舉的b的集合就是60.首先當b如果都取1,...