题意
求把 N∗M N ∗ M 的棋盘分割成若干个 1∗2 1 ∗ 2 的长方形,有多少种方案。
思路
我们可以用状态压缩
dp
d
p
来做,设
f[i][j]
f
[
i
]
[
j
]
为前第i行的状态为
j
j
时的方案,我们可以枚举一个为上一行的状态,然后判断这两行连在一起能不能满足分割成
1∗2
1
∗
2
长方形的要求然后进行转移。
每个状态的第
i
i
个数为就代表竖着一半的
1∗2
1
∗
2
长方形,
0
0
为其余情况。
要求满足&
k
k
为,保证每个数字
1
1
的下面为,说明每个竖着一半的长方形补完。
j|k
j
|
k
满足每个连续的
0
0
<script type="math/tex" id="MathJax-Element-1864">0</script>为偶数,说明分割成横着的长方形。对于这种情况,我们可以预处理。
代码
#include<cstdio>
int n, m, ok[4096];
long long f[12][4096];
bool odd, cnt;
int main() {
while (scanf("%d%d", &n, &m),n,m) {
for (int i = 0; i < 1 << m; i++) {
odd = cnt = 0;
for (int j = 0; j < m; j++)
if (i >> j & 1) odd |= cnt, cnt = 0;
else cnt ^= 1;
ok[i] = cnt | odd ? 0 : 1;//预处理连续0为偶数的状态
}
f[0][0] = 1;
for (int i = 1; i <= n; i++)
for (int j = 0; j < 1 << m; j++) {
f[i][j] = 0;
for (int k = 0; k < 1 << m; k++)
if (!(k & j) && ok[j | k])//判断转移
f[i][j] += f[i - 1][k];
}
printf("%lld\n", f[n][0]);
}
}