狀態壓縮動態規劃(狀壓DP)

2021-10-05 18:24:54 字數 2868 閱讀 1436

狀態壓縮動態規劃就是我們常說的狀壓dp,前兩天某廠實習生二面面試官隨手就給我抽了一道狀壓dp的題,我根本沒思路,sorry就寫了一行注釋。然後leetcode周賽最後一題又碰到了狀壓dp的題目,我一定要搞定這個型別的問題。加油加油!

狀壓dp說簡單也簡單,基本上就是用一串二進位制樹來表示當前情況 的狀態,例如舉個在別人的部落格裡看到的例子:

題目:在 n*n(n≤20)的方格棋盤上放置 n 個車(可以攻擊所在行、列),求使它們不能互相攻擊的方案總數。

通過數學方法很好理解,就是n的階乘,n!

那如果用動態規劃來解決呢?

我們可以把問題抽象一下,用一串二進位制數來表示當前狀態每一列上放置車的情況,比如在n=5

n=5n=

5的情況下,00010

00010

0001

0就代表第2列上已經放置了一輛車(從右往左數),注意一下,這個狀態表明的只是第二列上有一輛車,並沒有限制這一輛車在第幾行,其實放在第幾行對最後的結果並沒有什麼影響,可以看作是按行放置的順序可以不同,結果數是一樣的(我是這麼理解的)。我們用乙個陣列dp[

stat

us

]dp[status]

dp[sta

tus]

來表示sta

tu

sstatus

status

這個狀態下的可能方案數。初始條件的話,dp[

00000

]dp[00000]

dp[000

00]很明顯就只有一種情況,所以dp[

00000]=

1dp[00000]=1

dp[000

00]=

1。那麼問題要求的結果很明顯就是每一列都有一種車的情況,也就是dp[

11111

]dp[11111]

dp[111

11]。那麼我們只要找到遞推公式,就可以一點一點的把所有狀態都求出來。有一點值得注意的是,我們用來代表狀態的五位二進位制數是可以轉換為十進位制的,也就是說可以把它們看作是dp陣列的下標,例如00000就是0, 00011就是3這樣。也可以根據狀態查詢dp陣列找到要查詢的狀態的值。

那麼我們來看一看當所有列之中一共只有一列有車的情況下,它在dp陣列中的值為多少。比如狀態00010, 它是在00000狀態之上,在第二列上放了乙個車,所以它的方案數就是dp[00000]這麼多的方案數。所以dp[

00010]=

dp

[00000]=

1dp[00010]=dp[00000]=1

dp[000

10]=

dp[0

0000

]=1。同樣對於其他幾個只有乙個列有車的情況有dp[

10000]=

dp

[01000]=

dp

[00100]=

dp

[00001]=

1dp[10000]=dp[01000]=dp[00100]=dp[00001]=1

dp[100

00]=

dp[0

1000

]=dp

[001

00]=

dp[0

0001

]=1。

那麼我們再看所有列中有兩個列有車的狀態,他們的狀態下有多少種方案,例如狀態11000下,它的前乙個狀態可能是10000也可能是01000,所以它的dp值為這兩個狀態的和,也就是dp[

11000]=

dp

[10000]+

dp

[01000]=

2dp[11000]=dp[10000]+dp[01000]=2

dp[110

00]=

dp[1

0000

]+dp

[010

00]=

2,而五列裡有兩個車的狀態有c52

=10

c^2_5=10

c52​=1

0個,這十個狀態的dp值也就是對應的方案書都是2。

在看三個列有車的狀態,例如11100,它的上乙個狀態可能是11000或者10100或者01100這三種,所以它的可能性數就是對應的三種狀態的值的和。dp[

11100]=

dp

[11000]+

dp

[10100]+

dp

[01100

]dp[11100]=dp[11000]+dp[10100]+dp[01100]

dp[111

00]=

dp[1

1000

]+dp

[101

00]+

dp[0

1100

]。所以我們可以得出遞推公式:

d p[

stat

us]=

∑i=0

i

nd(s

tatu

s&(1

<

)dp[

stat

us^(

1<

]dp[status]=\sum_^{(1atus

^(1<

,這一部分便是找到放置第i+1位小車之前的狀態,舉個例子,比如說狀態11100, 它和00100異或的結果是11000,也就是在放置第三位小車之前的狀態,所以把所有位都進行一次這樣的操作,再把他們的狀態值求和,便是新的狀態值了。

我認為狀態壓縮動態規劃就是利用二進位制的性質來簡化動態規劃的一些操作的一種方法,感覺就像通過二進位制性質把當前狀態雜湊到乙個整數,然後在通過雜湊之前的狀態來獲取值再進行遞推的一種方法,以上就是我的理解,希望能給大家帶來幫助!(估計也沒人會看 23333)。

狀壓dp(總結)狀態壓縮

狀壓這個和二進位制分不開關係 所以,對於二進位制的熟悉是必不可少的技能 與操作,1不變,0變0 或操作,0不變,1變1 異或操作,0不變,1取反 取反操作,把每乙個二進位制位0變1,1變0 還有一些複雜操作可以根據這些去理解 狀態壓縮 所謂狀態壓縮就是把dp的每一次轉移時的狀態用二進位制來表示 或者...

動態規劃 狀態壓縮dp

if cnt 1 return false 用來判斷像01這種最後是0的情況 return true int main return 0 預處理所有狀態是否為合法狀態 include include include using namespace std typedef long long ll c...

動態規劃之四 狀壓dp

給出乙個n n型的方格棋盤。乙個棋子放在其中乙個格仔裡,那麼他的8個方向都不能放棋子,限制最多擺放的棋子個數為m,問最多有多少種放法。可以用乙個三維陣列來表示乙個狀態,表示所有前i行,已經擺了j個棋子,並且第i行擺放的狀態是s的所有方案。判斷約束條件,一行內不能有兩個棋子相鄰,第i 1行和第i行不能...