题意
给定 n * m 的方格棋盘, 用 1*2 的矩形不重叠地覆盖这个棋盘, 求覆盖满的方案数
题解
位运算结合状态压缩, 比较复杂
引用
二进制数(####)代表填完一行后这一行的状态,填满的地方为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 <bits/stdc++.h>
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
#define rg register
#define sc scanf
#define pf printf
typedef long long ll;
int n, m,
pos;
ll f[12][1 << 12];
void dfs ( int k, int last, int now ) {
if ( k == m ) f[pos][now] += f[pos - 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 ( ) { // freopen( "F:\\in\\.txt" , "r" , stdin );
while ( ~sc ( "%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 ( pos = 1; pos <= n; pos++ )
dfs ( 0, 0, 0 );
pf ( "%lld\n", f[n][(1 << m) - 1] );
}
return 0 ;
}