硬木地板

69 篇文章 0 订阅

硬木地板


Description

举行计算机科学家盛宴的大厅的地板为 M×N ( 1M9 , 1N9 )的矩形。
现在必须要铺上硬木地板砖。
可以使用的地板砖形状有两种:
1) 2×1 的矩形砖
2) 2×2 中去掉一个 1×1 的角形砖你需要计算用这些砖铺满地板共有多少种不同的方案。
注意:必须盖满,地板砖数量足够多,不能存在同时被多个板砖覆盖的部分。


Input

包含 M N


Output

输出方案总数,如果不可能那么输出 0


Sample Input

2 3


Sample Output

5


Solution

f[i][s] 表示把前 i1 行覆盖满、第 i 行覆盖状态为 s 的覆盖方案数,

得到的递推式:
f[0][111]=1
f[i][s1]=f[i1][s2]

其中 (s1,s2) 整体作为一个放置方案。

DFS,我们有5 个参数,分别为: p (当前列号),s1 s2 (当前行和对应的上一行的覆盖情况), b1 b2 (上一列的放置对当前列两行的影响,影响为 1 否则为 0)。

列表给出:

这里写图片描述

容易看出,在本题中此种 DFS 方式实现很简单。
考虑其复杂度,因为L 形骨牌不太规则,笔者没能找到一维的方案数的递推公式,因此无法给出复杂度的解析式。
但当 m=9 时,算法共生成放置方案 79248 个,
则对于 n=m=9 ,算法的复杂度为 O(979248) ,可以瞬间出解。


Code

#include <iostream>
#include <cstdio>
#include <cstring>

#define LL long long

using namespace std;

int head[5000],nxt[600000],data[600000];
LL f[20][5000],ans;

int m,n,cnt;

void add(int x,int y){
    nxt[cnt]=head[x];data[cnt]=y;head[x]=cnt++;
}

void dfs(int s1,int s2,bool p1,bool p2,int step){
    if(step==m){
        if(!p1&&!p2){
            add(s1,s2);
        }
        return;
    }
    dfs((s1<<1)^(1^p1),(s2<<1)^p2,0,0,step+1);
    if(!p1){
        dfs(s1<<1,(s2<<1)^p2,1,1,step+1);
    }
    if(!p2){
        dfs((s1<<1)^(1^p1),(s2<<1)|1,1,1,step+1);
        dfs((s1<<1)^(1^p1),(s2<<1)|1,0,1,step+1);
    }
    if(!p1&&!p2){
        dfs((s1<<1),(s2<<1)|1,0,0,step+1);
        dfs((s1<<1),(s2<<1)|1,0,1,step+1);
        dfs((s1<<1),(s2<<1)|1,1,0,step+1);
    }
}

int main(){

    freopen("floor2.in","r",stdin);
    freopen("floor2.out","w",stdout);

    memset(head,-1,sizeof head);

    scanf("%d%d",&m,&n);

    if(m>n)m^=n^=m^=n;

    const int limit=(1<<m);

    dfs(0,0,0,0,0);
    f[0][limit-1]=1;
    for(int i=1;i<=n;i++)
        for(int j=0;j<limit;j++)
            for(int k=head[j];k!=-1;k=nxt[k])
                f[i][j]+=f[i-1][data[k]];
    printf("%lld\n",f[n][limit-1]);
    return 0;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值