15 蒙德里安的夢想 狀態壓縮DP

2022-09-16 14:33:11 字數 2838 閱讀 5926

位運算 + 二進位制表示狀態 = 狀態壓縮dp

先把橫著的小方塊放好,然後剩下位置用豎著的小方塊填充

然後就轉化為求橫著擺放小方塊的方案數

按列來求

狀態表示:

dp[i][j]表示所有擺到了第i列,然後上一列伸出來的小方塊的狀態是j的情況下,總的方案數

狀態轉移:

列舉一下i - 1列的狀態

比如說當前狀態是j = 00001

然後上乙個狀態i - 1是k = 10010

從i - 1列伸到第i列的:j = 00001

從i - 2列伸到第i - 1列的:k = 10010

位運算的預備知識

與運算    &

或運算    |

條件一:不能有衝突。

也就是需要判斷(j & k)== 0,若等於0,表示沒有衝突

條件二:第i - 1列空餘格仔一定是連續的,且是偶數,因為要豎著放小方塊

j | k裡面,所有0的位置,就是第i - 1列所有空白的格仔

就是j | k裡面不能存在連續奇數個0

只要滿足這兩個條件,就可以轉移過來

把所有滿足條件的k加起來,就是狀態轉移方程

狀態數量:11 * 2 ^ 11

轉移數量:2 ^ 11

時間複雜度:11 * 2 ^ 11 *2 ^ 11 = 4 * 10 ^ 7

2023年7月31日複習更新:關於dp[0][0]為什麼初始化為1

在下面**31行,求dp陣列的過程時,是從第1列開始列舉的,但是之後需要用到dp[i - 1]

從dp陣列的定義入手考慮,dp[i][j]表示所有擺到了第i列,然後上一列伸出來的小方塊的狀態是j的情況下,總的方案數

i的含義是這是第i列

j的含義是從第i - 1列伸出來的小方塊的狀態是j

當i = 0時,i - 1 = -1,第-1列不會有小方塊,所以第i列的狀態一定是0

dp[0][0] = 1表示不放也是一種方案,這是dp問題統計方案數的重點

遇到1以後,連續奇數個0已經結束了,新開始一段

20 } else23}

24if (cnt & 1) 27}

28//

然後是dp的過程

29 memset(dp, 0, sizeof dp); //

把dp陣列置為0

30 dp[0][0] = 1; //

邊界情況

31for (int i = 1; i <= m; i++) 37}

38}39}

40 cout << dp[m][0] << endl; //

答案41}42

return0;

43 }

狀態壓縮dp 蒙德里安的夢想

1 n,m 11 輸入樣例 1 21 3 1 42 2 2 32 4 2 11 4 11 0 0輸出樣例 include using namespace std const int n 12,m 1 n int st m long long f n m intmain else cnt if cnt...

狀態壓縮DP例題 蒙德里安的夢想

1.棋盤問題 1.1 蒙德里安的夢想 將一種狀態用二進位制來表示。對於此題,由於小方塊是1 2,如果先擺放橫著的,故在擺放第i列時,只需要考慮第i 1列有沒有衝突的。然後在插空擺放豎著的,如果橫向擺放已經確定,那麼豎向的也是確定的,即 總方案數 橫向擺放的方案數。要判斷擺放是否合法,即不能有空餘的小...

蒙德里安的夢想

求把n m的棋盤分割成若干個1 2的的長方形,有多少種方案。例如當n 2,m 4時,共有5種方案。當n 2,m 3時,共有3種方案。如下圖所示 輸入格式 輸入包含多組測試用例。每組測試用例佔一行,包含兩個整數n和m。當輸入用例n 0,m 0時,表示輸入終止,且該用例無需處理。輸出格式 每個測試用例輸...