广场铺砖问题

来源:互联网 发布:java发送delete请求 编辑:程序博客网 时间:2024/06/10 03:00

广场铺砖问题

[1]:

问题描述 Problem Decsription

有一个 WH 列的广场,需要用 12 小砖铺盖,小砖之间互相不能重叠,问有多少种不同的铺法?


输入描述 Input Description

只有一行 2 个整数,分别为 WH(1WH11)


输出描述 Output Description

只有 1 个整数,为所有的铺法数。


输入样例 Sample Input

2 4


输出样例 Sample Output

5


分析 I Think

状态压缩。直接搜索每一个状态可能转移到的所有状态,在进行 DP 即可。


代码 Code

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef long long LL;bool link[(1<<11)+3][(1<<11)+3];LL f[13][(1<<11)+3];int n,m;void dfs(int,int,int);int main(){    scanf("%d%d",&n,&m);    for(int i=0;i<(1<<m);++i)        dfs(i,0,0);    f[0][0] = 1;    for(int i=0;i<n;++i)        for(int j=0;j<(1<<m);++j)            if(f[i][j])                for(int k=0;k<(1<<m);++k)                    if(link[j][k])                        f[i+1][k] += f[i][j];    printf("%lld",f[n][0]);    return 0;}void dfs(int f1,int step,int f2){    if(step == m){        link[f1][f2] = true;        return ;    }    if(f1&(1<<step)){        dfs(f1,step+1,f2);        return ;    }    if(!(f1&(1<<(step+1))) && step+1<m)        dfs(f1,step+2,f2);    dfs(f1,step+1,f2|(1<<step));}


[2]

问题描述 Problem Description

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


输入描述 Input Description

一行,两个整数: M,N


输出描述 Output Description

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


样例输入 Sample Input

2 3


样例输出 Sample Output

5


分析 I Think

同上,直接搜索每一个状态可能转移到的所有状态,在进行 DP 即可。
不过这个搜索就有些不同。因为有角型砖,所以 dfs 时还要多两个参数,表述当前行和上一行的当前列有没有被角型砖或者是横着放的矩形砖覆盖而多出一个角。


代码 Code

#include <cstdio>#include <cstring>#include <algorithm>using namespace std;typedef long long LL;int head[1<<11],nxt[1<<20],to[1<<20],tot=1;LL f[10][1<<10];int n,m;void dfs(int,int,int,int,int);void add(int,int);int main(){    scanf("%d%d",&n,&m);    dfs(0,0,0,0,0);    f[0][(1<<m)-1] = 1;    for(int i=0;i<n;++i)        for(int j=0;j<(1<<m);++j)            if(f[i][j])                for(int k=head[j];k;k=nxt[k])                    f[i+1][to[k]] += f[i][j];    printf("%lld",f[n][(1<<m)-1]);    return 0;}void dfs(int s1,int s2,int b1,int b2,int step){    if(step == m){        if(!b1 && !b2)            add(s2,s1);        return ;    }    dfs(s1|(b1<<step),s2|((1-b2)<<step),0,0,step+1);    if(!b1 && !b2){        dfs(s1|(1<<step),s2,0,0,step+1);        dfs(s1|(1<<step),s2,1,0,step+1);        dfs(s1|(1<<step),s2,0,1,step+1);    }    if(!b1){        dfs(s1|(1<<step),s2|((1-b2)<<step),1,0,step+1);        dfs(s1|(1<<step),s2|((1-b2)<<step),1,1,step+1);    }    if(!b2)        dfs(s1|(b1<<step),s2,1,1,step+1);}void add(int from,int tp){    ++tot;nxt[tot]=head[from];head[from]=tot;to[tot]=tp;}
0 0