狀態壓縮動態規劃,就是我們俗稱的狀壓dp,是利用計算機二進位制的性質來描述狀態的一種dp方式,狀壓其實是一種很暴力的演算法,因為他需要遍歷每個狀態,所以將會出現2^n的情況數量,不過這並不代表這種方法不適用:一些題目可以依照題意,排除不合法的方案,使一行的總方案數大大減少從而減少列舉
在學習狀壓dp前,必須先要學習一下位運算
①左移: 左移一位,就相當於某數乘以2,則左移n位,相當於某數乘以2ⁿ
②右移: 右移一位,就相當於某數除以2,則左移n位,相當於某數除以2ⁿ
③與運算: 按位進行與運算,兩數同位均為1則對應位置為1,否則為0
④或運算: 按位進行或運算,兩數同位均為0則對應位置為0,否則為1
⑤非運算: 按位取反
【題目描述】
在 n×n 的棋盤上放 k 個國王,國王可攻擊相鄰的 8 個格仔,使它們無法互相攻擊的方案總數。
【輸入】
只有一行,包含兩個整數 n 和 k。
【輸出】
每組資料一行為方案總數,若不能夠放置則輸出 0。
【輸入樣例】
3
2
【輸出樣例】
16
【分析】
根據資料可知這是一道狀壓dp,根據我們所學的狀壓知識解決即可
首先,我們要進行預處理,數每個二進位制位上有多少個1,再逐漸判斷國王狀態是否合法
【**】
#include
using
namespace std;
typedef
long
long ll;
int n,m;
ll ans;
int k[(1
<<10)
+5],ka[
101]
;ll f[20]
[(1<<10)
+5][
100]
;//行,狀態,多少王
bool
bfs(
int x)
//判斷狀態是否合法(即不能在一行相鄰)
for(
int i=
1;i<=n;i++)if
(ka[i]==1
&&(ka[i-1]
==1||ka[i+1]
==1))
return0;
return1;
}void
count_king()
//數二進位制位上國王的個數
k[i]
=v;}
}boolpd(
int a,
int b)
//判斷狀態是否合法(即上下不能相鄰)
intmain()
}}for(
int j=
1;j<=n;j++
)for
(int i=
1;i<=(1
<;i++)if
(bfs
(i))ans+
=f[j]
[i][m]
; cout<}
推薦題目
題目題解
如果看了我的部落格還不太懂的話,你可以去以下兩個位置訪問
一般來說,資料範圍不超過20的題目,都可以考慮用狀壓dp來完成,不過其實狀壓dp的思想很好理解,只不過對於像我一樣的蒟蒻 來說很難實現罷了o(tωt)o o(╥﹏╥)o
謝謝**!囧 **ヽ( ̄▽ ̄)ノ┗( ▔, ▔ )┛ **
狀態壓縮動態規劃
動態規劃的狀態有時候比較難,不容易表示出來,需要用一些編碼技術,把狀態壓縮的用簡單的方式表示出來。典型方式 當需要表示乙個集合有哪些元素時,往往利用2進製用乙個整數表示。一般有個資料 n 16 或者 n 32 這個很可能就是狀態dp的標誌,因為我們要用乙個int的二進位制來表示這些狀態。要注意好這些...
動態規劃 狀態壓縮
這個題目的題意很容易理解,在乙個n m的格仔裡,我們現在有兩種型別的磚塊,1 2和 2 1,問一共有多少種方案,可以將整個n m的空間都填滿。最簡單的例子就是下面的了 程式設計之美中題目 某年夏天,位於希格瑪大廈四層的微軟亞洲研究院對辦公樓的天井進行了一次大規模的裝修.原來的地板鋪有 n m 塊正方...
狀態壓縮動態規劃
我們可以使用乙個01串a來表示乙個集合。對於數x x 0 用ax 0表示它不在該集合中,用ax 1表示它在該集合中。將01串a看作是乙個二進位制數,我們把它轉換為十進位制,就可以使用乙個十進位制整數來表示乙個實際使用二進位制方式表示的集合。這樣,我們可以使用位運算方便地處理集合的操作。交集兩個集合a...