狀壓dp小結

2022-09-19 03:00:14 字數 1362 閱讀 9865

狀壓dp,是用二進位制的性質來描述狀態的一種dp。

對於狀壓dp,我們要先了解一下位運算。

先看一道題:

在 \(n\times n\) 的棋盤上放 \(k\) 個國王,國王可攻擊相鄰的 8 個格仔,求使它們無法互相攻擊的方案總數。

對於全部資料,\(1≤n≤10,0≤k≤n^2\)

方法一:爆搜

時間複雜度:\(o(2^)\)

方法二:狀壓dp

那dp的狀態是什麼?

要表示每行的狀態,和第幾行,是不是要開dp[11][2][2][2][2][2][2][2][2][2][2]

那就非常麻煩。

於是考慮壓維。

我們發現後面的維度都是2,那是不是很像...

二進位制!

對,我們可以把後面的維數壓成二進位制!

然後原先的每個狀態現在對應二進位制的每一位!

然後我們就能巧妙解決了這個問題!

設 \(dp[i][j][s]\) 表示第 \(i\) 行放置方式為 \(s\) 前 \(i\) 行放置 \(j\) 個國王的方案數。

那,二進位制怎麼轉移啊?

我們發現,國王不能左右攻擊,也就是s&(s<<1)==0

國王不能上下攻擊,就是s&c==0

國王不能斜著攻擊,就是s&(c<<1)=0s&(c>>1)=0

那當滿足上述條件的時候,是不是就可以從 \(dp[i-1][j-qiu(s)][c]\) 轉移到 \(dp[i][j][s]\) 了?

然後似乎就做出來了。

#includeusing namespace std;

#define int long long

int n, m, i, j, k;

int dp[15][150][1050];

int ans, a, b;

int qiu(int x) //求這個狀態有多少個國王

signed main()

int suan(int x)

signed main()

)\)#includeusing namespace std;

#define int long long

int n, m, i, j, k;

int dp[10010][50];

int f[10010][50];

int p, ans, l, r, e;

int a, b;

int du()

{ int x; scanf("%lld", &x);

if(x以上例題對應一本通提高篇題目。

狀壓dp 玉公尺田 狀壓dp

相關 強相關 327.玉公尺田 狀壓dp 小國王 狀壓dp 是井字形,本題是十字形。思路 狀態計算 時間複雜度 n 2 n 2n o n 22n 12 2 24n 2 n 2 n o n2 12 2 n 2n 2 n o n22n 12 224 看著妥妥超時,但是裡面合法狀態很少 依舊可以過 在此,...

狀壓dp小記

鋪磚 題意 現有nm的一塊地板,需要用12的磚塊去鋪滿,中間不能留有空隙。問這樣方案有多少種 include using namespace std typedef long long ll const int maxn 1 11 int n,m,state ll dp 15 maxn s1表示本行...

狀壓dp學習

p2704 炮兵陣地 1038 裁玻璃 狀壓dp是一種非常暴力的做法,列舉所有可能的狀態,找到要求的最佳狀態,與一般dp不同,前一項與後一項有一些複雜的狀態關係。dp的引數 物品個數 行數等 當前狀態 上乙個狀態 將abc的有無表示成乙個8個狀態,列舉所有組,列舉上乙個狀態,得到當前狀態的最優解 i...