题意

  • n行m列矩形,用1*2的矩形块填充,有多少种填充方案

思路

  • 依然是棋盘放置一类的问题,考虑一行一行放
  • 对于每一行,上一行竖着放的地方一定放不了,上一行横着放的地方可以竖着放也可以横着放,行内不可能的是把一个横着的拆开,两行间不可能的是,上一行竖着,这一行还放东西
  • 设计状态:横着放记为0,竖着放记为1,竖着放的下一行记为0
    • 这样子新st和旧st做与就可以排除行间冲突
    • 而对于行内,除了上一行是1的位置任意枚举,但是连续的0必须是偶数个,将新st和旧st做或运算,排除原来的1带来的影响,检查剩下的0是不是偶数个连续即可

代码

#include<bits/stdc++.h>
#define int long long
using namespace std;

/**
 * 还是一行一行的放,横着放记为0,竖着放记为1
 * 如果上一行是1,下一行就是0,如果上一行是0,下一行0必须偶数个
 * 枚举新一行的st,检查是否符合上一行规则
 * 两行的与必须是0,否则说明有两格1
 * 两行的或中0必须是偶数个,用或来排除上行1下行0的情况
 * 011101100
 * 100010011
 * 1???1
 * 
 * dp[i][st]表示第i行状态为st的情况
 * 
 */



int n,m;
int dp[15][1<<15];
int judge(int st){
    int cnt=0;
    for(int i=1;i<=m;i++){
        if(st&1){
            if(cnt%2)return -1;
            cnt=0;
        }else
            cnt++;
        st>>=1;
    }
    return cnt%2?-1:1;
}

signed main(){
    while(1){
        cin >> m >> n;
        if(m==n&&n==0) break;
        memset(dp,0,sizeof(dp));
        dp[0][0]=1;
        for(int i=1;i<=n;i++){
            for(int cur=0;cur<=(1<<m)-1;cur++){
                for(int lst=0;lst<=(1<<m)-1;lst++){
                    if(cur&lst) continue;
                    if(judge(cur|lst)==-1)continue;
                    dp[i][cur]+=dp[i-1][lst];
                }
            }
        }
        cout << dp[n][0] << endl;
    }
    return 0;
}