题意:
给出n*m (1≤n、m≤11)的方格棋盘,用1*2的长方形骨牌不重叠地覆盖这个棋盘,求覆盖满的方案数。
Solution:
位运算+状态压缩+dp
二进制数(####)代表填完一行后这一行的状态,填满的地方为1,未填的地方为0。
显然在填第i行时,能改变的仅为第i-1行和第i行,因此要满足在填第i行时,第1~i-2行已经全部填满。
DFS一行的状态,要是填完第i行时,第i-1行被填满。
因此两行的状态(p1,p2)满足,~p1=p2;
DFS出所有满足条件的状态对(P1,P2)
①第i行第k位为1,第i-1行第k位为0。(一块骨牌竖直放置)
dfs(k+1,last<<1,now<<1 | 1)
②第i行第k位为0,第i-1行第k位为1。 (第i行空出第k位)
dfs(k+1,last<<1 | 1,now<<1)
③骨牌横向放置。
bfs (k + 2, last << 2 | 3, now << 2 | 3)
转移方程:F[i][sp1]=∑f[i-1][sp2]
代码:
#include <iostream> #include <cstring> #include <cstdio> #define LL long long using namespace std; int n, m, x; LL f[12][1 << 12]; void dfs (int k, int last, int now) { if (k ==m ) f[x][now] += f[x - 1][last]; if (k > m) return; dfs (k + 1, last << 1, now << 1 | 1); dfs (k + 1, last << 1 | 1, now << 1); dfs (k + 2, last << 2 | 3, now << 2 | 3); } int main() { while (~scanf ("%d %d", &n, &m) ) { if (n == 0) break; if (n > m) swap (n, m); memset (f, 0, sizeof f); f[0][ (1 << m) - 1] = 1; for (x = 1; x <= n; x++) dfs (0, 0, 0); printf ("%lld\n", f[n][ (1 << m) - 1]); } }