學習筆記 狀態壓縮DP

2022-07-17 07:45:08 字數 1925 閱讀 9842

我們知道,用dp解決乙個問題的時候很重要的一環就是狀態的表示,一般來說,乙個陣列即可儲存狀態。但是有這樣的一些題 目,它們具有dp問題的特性,但是狀態中所包含的資訊過多,如果要用陣列來儲存狀態的話需要四維以上的陣列。於是,我們就需要通過狀態壓縮來儲存狀態,而 使用狀態壓縮來儲存狀態的dp就叫做狀態壓縮dp。

一道例題:

hoj 2662

有乙個n*m的棋盤(n、m≤80,n*m≤80)要在棋盤上放k(k≤20)個棋子,使得任意兩個棋子不相鄰(每個棋子最多和周圍4個棋子相鄰)。求合法的方案總數。

直接考慮解決這個問題並不容易,我們先來考慮這個問題的退化形式:

現在我們令n=1。則我們可以很容易的想到狀態轉移方程:

設dp[i][j][0]表示當前到達第i列,一共使用了j個旗子,且當前格仔的狀態為不放的狀態總數,類似的 dp[i][j][1]就是當前格仔的狀態為放的狀態總數。

那麼狀態轉移方程就是

dp[i][j][0]=dp[i-1][j][1]+dp[i-1][j][0];

dp[i][j][1]=dp[i-1][j-1][0];

當n=1的時候這個問題無疑是非常簡單的,但是如果我們想模仿這種做法來解決原問題的話,就會遇到這樣的問題:如何來表示當前行的狀態?

昨天已經提到了一些狀態壓縮的知識,如果看懂了的話,應該已經明白怎麼做了。

對於每一行,如果把沒有棋子的地方記為0,有棋子的地方記為1,那麼每一行的狀態都可以表示成乙個2進製數,進而將其轉化成10進製。

那麼這個問題的狀態轉移方程就變成了

設dp[ i ] [ j ][k ]表示當前到達第i列,一共使用了j個棋子,且當前行的狀態在壓縮之後的十進位制數為k 時的狀態總數。那麼我們也可以類似的寫出狀態轉移方程:

dp[ i ][ j ][ k ]=sum( dp[ i-1][ j-num(k) ][ w ] )   num(k)表示 k狀態中棋子的個數,w表示前一行的狀態。

雖然寫出了狀態轉移方程,但是還是有很多細節問題需要解決:比如,如何保證當前狀態是合法的?

最基本的做法是:首先判斷k狀態是否合法,也就是判斷在這一行中是否有2個旗子相鄰,然後列舉上一行的狀態w,判斷w狀態是否合法,然後判斷k狀態和w狀態上下之間是否有相鄰的棋子。

當然這樣做的時間複雜度是很高的,也就是說有很多地方可以優化,比如:判斷每一行狀態是否合法,可以在程式一開始判斷然後儲存結果,判斷k狀態和w狀態上下之間是否有相鄰的棋子,可以利用位運算,if(k&w)說明上下之間有相鄰的棋子等等。

講到這裡,這道題目的做法已經很明確了,請大家自行完成。

另一道例題:

tsp問題

給你n個城市和城市之間的通路的長度,請你找出一條經過所有城市一次且僅經過一次的路線,使得這條路線的長度最短。

問題分析,如果要設計乙個狀態的話,顯然狀態與已經走過的城市和你當前所在的城市有關,現在,按照一定的順序給每個城市乙個編號,如果已經走過的城市記為1,沒走過的城市記為0,那麼已經走過的城市的狀態就可以壓縮成乙個數。所以,該題目的狀態表示為:

dp[i][j]表示已經走過的城市為i,當前所在的城市為j的最短路程。

相應的狀態轉移方程為dp[ i ][ j]=min( dp[ i ^ (1狀態壓縮dp的特點:

狀態中的某一維會比較小,一般不會超過15,多了的話狀態數會急劇上公升而無法壓縮,一般來說需要狀態壓縮的也就是這一維。

狀態壓縮dp的常見優化:

預處理是最常見的優化,尤其是在棋盤類問題上,比如說例題1,如果我們想進一步提高效率,我們還可以預處理出狀態之間是否可以轉移而不用在每一次轉移中判斷。

靈活運用位運算,例題1中if(k&w)就是乙個很好的例子。

除了上述2道題目以外,我還推薦:

hoj•   2188 wordstack

•   2798 globulous gumdrops

•   2800 artillery assignment

這一類dp對於編碼能力要求比較高,請大家盡力而為。

**

狀態壓縮 DP 學習筆記

對於乙個全集 u 的任意乙個子集 a u 我們可以用乙個n位的二進位制數來表示這乙個集合。其中,末位第 i 位數為 0表示 ai 不存在於該子集中,為 1 表示 ai 存在於該子集中。例如 全集 u 子集 a 那麼我們可以用 10101 2 來表示子集 a 對於全集 u的任意兩個子集 a b的二進位...

狀態壓縮DP

首先,我們以一道狀壓經典題tsp來引入。tsp問題 一張圖上有n個點,給定相應的鄰接矩陣,需要求出從0號節點出發,經過且只經過每個頂點一次,最後仍回到0號節點的最小邊權。思路 假設現在已訪問過的頂點集合 起點0當作還未訪問過的頂點 為s,當前所在頂點為v,用dp s v 表示從v出發訪問剩餘的所有頂...

狀態壓縮DP

theme 給定乙個n m的玉公尺田,1 n,m 12。值為0表示不能在該塊種草,為1表示可以。現在要在其上中若干草地,要求任意草地間不相鄰 沒有公共邊 問不考慮草地個數的情況下,有多少種種植的方案?solution 用dp。又範圍很小,所以考慮狀態壓縮dp,另dp i j 表示從前i行種植,最後一...