狀態壓縮動態規劃【DP】
一、概述
1.狀態壓縮
狀態壓縮就是使用某種方法,簡明扼要地以最小代價來表示某種狀態,通常是用一串01數字(二進位制數)來表示各個點的狀態。這就要求使用狀態壓縮的物件的點的狀態必須只有兩種,0 或 1;當然如果有三種狀態用三進位制來表示也未嘗不可。
2.使用條件
從狀態壓縮的特點來看,這個演算法適用的題目符合以下的條件:
解法需要儲存一定的狀態資料(表示一種狀態的一個數據值),每個狀態資料通常情況下是可以通過2進位制來表示的。這就要求狀態資料的每個單元只有兩種狀態,比如說棋盤上的格子,放棋子或者不放,或者是硬幣的正反兩面。這樣用0或者1來表示狀態資料的每個單元,而整個狀態資料就是一個一串0和1組成的二進位制數。
解法需要將狀態資料實現為一個基本資料型別,比如int,long等等,即所謂的狀態壓縮。狀態壓縮的目的一方面是縮小了資料儲存的空間,另一方面是在狀態對比和狀態整體處理時能夠提高效率。這樣就要求狀態資料中的單元個數不能太大,比如用int來表示一個狀態的時候,狀態的單元個數不能超過32(32位的機器),所以題目一般都是至少有一維的資料範圍很小。
3.狀壓DP
狀壓DP,顧名思義,就是使用狀態壓縮的動態規劃。
動態規劃問題通常有兩種,一種是對遞迴問題的記憶化求解,另一種是把大問題看作是多階段的決策求解。這裡用的便是後一種,這帶來一個需求,即儲存之前的狀態,再由狀態及狀態對應的值推演出狀態轉移方程最終得到最優解。
二、位運算
一般基礎的狀壓就是將一行的狀態壓成一個數,這個數的二進位制形式反映了這一行的情況。由於使用二進位制數來儲存被壓縮的狀態,所以要用到神奇的二進位制位運算操作,將一個十進位制數轉成二進位制進行位運算操作再轉回十進位制數。
名稱 | 運算子 | Pascal樣式 | 簡記法則 |
---|---|---|---|
按位與 | & | and | 全一為一,否則為零 |
按位或 | | | or | 有一位一,否則為零 |
按位取反 | ~ | not | 是零則一,是一則零 |
按位異或 | ^ | xor | 不同則一,相同則零 |
左移位 | << | shl | a<<k等價於a*2^k |
右移位 | >> | shr | a>>k等價於a/2^k |
注:在涉及到位運算時,一定要注意位運算的優先順序。該加的括號一定要加
定義狀態(例如) 求每一種放法的揹包價值,狀態應該是這n件物品的放與不放的情況。
最容易想到的是開個n維陣列,第i個維度的下標如果是1的話代表放第i件物品,0的話代表不放第i件物品;
但是這樣很容易造成空間浪費,而且多維陣列也不好開;
我們仔細觀察就會發現,每件物品有放與不放兩種選擇;假設我們有5件物品的時候,用1和0代表放和不放
如果這5件物品都不放的話,那就是00000;
如果這5件物品都放的話, 那就是11111;
看到這,我們知道可以用二進位制表示所有物品的放與不放的情況;如果這些二進位制用十進位制表示的話就只有一個維度了。而且這一個維度能表示所有物品放與不放的情況;這個過程就叫做狀態壓縮;
注:先簡單寫一下 回頭再改一下