硬木地板

来源:互联网 发布:js给元素赋值 编辑:程序博客网 时间:2024/03/29 07:14

硬木地板


Description

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


Input

包含 MN


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 (当前列号),s1s2 (当前行和对应的上一行的覆盖情况),b1b2 (上一列的放置对当前列两行的影响,影响为 1 否则为 0)。

列表给出:

这里写图片描述

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


Code

#include <iostream>#include <cstdio>#include <cstring>#define LL long longusing 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 0