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

2021-10-19 17:21:40 字數 1637 閱讀 9657

1. 棋盤問題

1.1 蒙德里安的夢想

將一種狀態用二進位制來表示。

對於此題,由於小方塊是1*2,如果先擺放橫著的,

故在擺放第i列時,只需要考慮第i-1列有沒有衝突的。

然後在插空擺放豎著的,如果橫向擺放已經確定,

那麼豎向的也是確定的,即:總方案數 = 橫向擺放的方案數。

要判斷擺放是否合法,即不能有空餘的小方塊。

那麼:在擺放第i列豎向的時候,需要判斷,第i列中的數個連續的的空白位置,

是否是偶數個( 偶數個才能正好將豎向的方塊擺滿)。

對於一列來說,共有2

n2^n

2n個狀態的可能。

對於i列是否與i-1列衝突,j&k == 0k為第i-1列的狀態(確定合法),j為第i列的狀態(不確定是否合法))

對於判斷某乙個狀態中的空白位置是否是偶數個,預處理即可——遍歷2

n2^n

2n個狀態,將每種狀態是否可行,放到dp中(只是乙個標記陣列),j|k是第i列 和第i-1合起來之後的狀態,看這個狀態的空白位置是否合法。

#include #include #include using namespace std;

const int n = 12, m = 1 << n; // 一位代表當前行的狀態 所以要1 << n 個狀態

int n, m;

long long f[n][m];

bool dp[m]; // 標記此狀態下空餘的格仔數是否是偶數個 偶數個就可以豎著放

int main()

cnt = 0;

}else

cnt++;

// 最後乙個

if (cnt % 2 == 1)

dp[i] = false;

}memset(f, 0, sizeof f);

f[0][0] = 1;

// m列

for (int i = 1; i <= m; i++)

// 列舉i列每一種狀態

for (int j = 0; j < 1 << n; j++)

// 列舉i-1列每一種狀態

for (int k = 0; k < 1 << n; k++)

if ((j & k) == 0 && dp[j | k])

f[i][j] += f[i - 1][k]; //那麼這種狀態下它的方案數等於之前每種k狀態數目的和

cout << f[m][0] << endl;

}return 0;

}

狀態壓縮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...

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

位運算 二進位制表示狀態 狀態壓縮dp 先把橫著的小方塊放好,然後剩下位置用豎著的小方塊填充 然後就轉化為求橫著擺放小方塊的方案數 按列來求 狀態表示 dp i j 表示所有擺到了第i列,然後上一列伸出來的小方塊的狀態是j的情況下,總的方案數 狀態轉移 列舉一下i 1列的狀態 比如說當前狀態是j 0...

蒙德里安的夢想

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