蒙德里安的梦想

题面
求把 NM 的棋盘分割成若干个12的的长方形,有多少种方案。

例如当N=2,M=4时,共有5种方案。当N=2,M=3时,共有3种方案。

输入格式
输入包含多组测试用例。

每组测试用例占一行,包含两个整数N和M。

当输入用例N=0,M=0时,表示输入终止,且该用例无需处理。

输出格式
每个测试用例输出一个结果,每个结果占一行。

数据范围
1≤N,M≤11
输入样例:
1 2
1 3
1 4
2 2
2 3
2 4
2 11
4 11
0 0
输出样例:
1
0
1
2
3
5
144
51205

题解:
首先通过预处理排除冗余状态,初状态预设为第一行的状态。
将横着放设置为11,竖着放设置为10
采取 阶段->状态->决策的循环顺序
转移条件是相邻两行不能出现00的状况
并且两行同时横着放的状态为可行状态。

#include<bits/stdc++.h>
#define maxx (1<<11)-1
using namespace std;
int c[2<<12];
long long f[12][2<<12];
bool check(int x){
    int t=0;
    while(x){
        if(x&1){
            t++;
        } 
        else{
            if(t&1) return 0;
            t=0;
        }
        x>>=1;
    } 
    if(t&1)
        return 0;
    return 1;
}

int n,m;
int main(){
    for(int i=0;i<=maxx;i++){
        if(check(i)) c[i]=1;
    }
    while(scanf("%d%d",&n,&m)!=EOF){
        if(n==0 && m==0) break;
        if(m>n) swap(m,n);
        if((n*m)&1){
            printf("0\n");
            continue;
        }
        memset(f,0,sizeof(f));
        for(int i=0;i<=((1<<m)-1);i++){
            if(check(i)) f[1][i]=1;
        } 
        for(int i=2;i<=n;i++){
            for(int j=0;j<=((1<<m)-1);j++){
                for(int k=0;k<=((1<<m)-1);k++){
                    if( (j|k) != ((1<<m)-1) ) continue;
                    if(!c[j&k]) continue;
                    f[i][k]+=f[i-1][j]; 
                }
            }
        }
        printf("%lld\n",f[n][(1<<m)-1]);
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值