硬木地板
Description
举行计算机科学家盛宴的大厅的地板为
M×N
(
1≤M≤9
,
1≤N≤9
)的矩形。
现在必须要铺上硬木地板砖。
可以使用的地板砖形状有两种:
1)
2×1
的矩形砖
2)
2×2
中去掉一个
1×1
的角形砖你需要计算用这些砖铺满地板共有多少种不同的方案。
注意:必须盖满,地板砖数量足够多,不能存在同时被多个板砖覆盖的部分。
Input
包含
M
和
Output
输出方案总数,如果不可能那么输出 0 。
Sample Input
2 3
Sample Output
5
Solution
用
得到的递推式:
f[0][1…11]=1
f[i][s1]=∑f[i−1][s2]
其中 (s1,s2) 整体作为一个放置方案。
DFS,我们有5 个参数,分别为:
p
(当前列号),
列表给出:
容易看出,在本题中此种 DFS 方式实现很简单。
考虑其复杂度,因为L 形骨牌不太规则,笔者没能找到一维的方案数的递推公式,因此无法给出复杂度的解析式。
但当
m=9
时,算法共生成放置方案
79248
个,
则对于
n=m=9
,算法的复杂度为
O(9∗79248)
,可以瞬间出解。
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;
}