/*1.定义一下:方块内放置长方体的上半部分,叫状态1,其余为0.
2.i,j的枚举顺序不是个人习惯问题,根据二进制位数来看,大的数在左边,于是将大的数放在左边.*/
#include<bits/stdc++.h>
using namespace std;
typedef long long LL;
const int N = 1 << 12;
LL cur[N], nxt[N];
int n, m;
int main() {
while(scanf("%d%d", &n, &m)) {
if(!n && !m) break;
cur[0] = 1;
for(int i = n - 1; i >= 0; i --)
for(int j = m - 1; j >= 0; j --) {
//枚举每一个状态
for(int s = 0; s < (1 << m); s ++){
//新状态的当前位置放了上半部分, 确保正上方的格子不是1
if((s >> j) & 1)
nxt[s] = cur[s & ~(1 << j)];
else {
LL tmp = 0;
/*尝试横放,记得范围
横放的时候由以下状态转移过来:第j + 1位、第j位都为0.状态1的格子插头方向向下不向右.
放完之后第j + 1、j位都是0……所以要保证s的第j + 1位是0,
因为我们这一轮只能改变第j位上的值,第j + 1位上的信息是确定的
所以想要有一个从第j + 1 位伸过来的插头的话,一定要先确保第j + 1位为0,
然后由第j + 1位是1的上一轮状态转移过来(将原本放心向下的改为向右
很妙对不对?*/
if(j + 1 < m && !((s >> (j + 1)) & 1))
tmp += cur[s | 1 << (j + 1)];
//尝试竖放,记得范围
if(i + 1 < n)
tmp += cur[s | 1 << j];
nxt[s] = tmp;
}
}
swap(cur, nxt);
}
printf("%lld\n", cur[0]);
}
return 0;
}
[题]蒙德里安的梦想 —— [简单] —— 标签:# 插头DP
最新推荐文章于 2021-12-20 16:27:14 发布