题意:
举行计算机科学家盛宴的大厅的地板为 M x N (1<=M<=9, 1<=N<=9)的矩形。现在必须要铺上硬木地板砖。可以使用的地板砖形状有两种:
1) 2x1的矩形砖
2) 2x2中去掉一个1x1的角形砖
你需要计算用这些砖铺满地板共有多少种不同的方案。
注意:必须盖满,地板砖数量足够多,不能存在同时被多个板砖覆盖的部分
分析:
周伟 《状态压缩》 里面的例题 http://wenku.baidu.com/view/4cd4891eb7360b4c2e3f6427.html
//AC CODE:
#include <stdio.h> #include <stdlib.h> #include <string.h> #define maxn 10 typedef long long lld; lld f[maxn][(1<<maxn)-1];//状态为f[i][s]前i-1行已覆盖,第i行状态为s时的总数 lld n,m,tot; void dfs(lld t,lld curRowStk,lld preRowStk,lld b1,lld b2,lld p) { //t当前行 //curRowStk为当前行 //preRowStk前一行, //b1为当前行在p列填完时对后一列(p+1)的影响,有没有把后一列给占了,占了为1,反之为0 //b2为i-1行对后一列的影响 //p为当前多在列 if (p>m)//结束条件 { if (b1==0 && b2==0) //注意条件 f[t][curRowStk]+=f[t-1][preRowStk]; return ; } if (b1==0 && b2==0)// 1 { // 1 dfs(t,curRowStk<<1|1,preRowStk<<1 ,0,0,p+1); //第1种状况 竖着 //curRowStk<<1|1 即为把curRowStk的二进制表示后面加上一个1,对于本题来说就是(p+1)列上放置, //preRowStk<<1 即为把preRowStk的二进制表示后面加上一个0,对于本题来说就是(p+1)列上不放置。 dfs(t,curRowStk<<1|1,preRowStk<<1|1,1,0,p+1); //第2种状况 横着 dfs(t,curRowStk<<1|1,preRowStk<<1 ,1,0,p+1); //第3种状况 少右上角 dfs(t,curRowStk<<1|1,preRowStk<<1|1,1,1,p+1); //第4种状况 少左上角 dfs(t,curRowStk<<1 ,preRowStk<<1 ,1,1,p+1); //第5种状况 少左下角 dfs(t,curRowStk<<1|1,preRowStk<<1 ,0,1,p+1); //第6种状况 少右下角 dfs(t,curRowStk<<1 ,preRowStk<<1|1,0,0,p+1); //第7种状况 不放 return ; } if (b1==0 && b2==1)// 1 1 { // 1 dfs(t,curRowStk<<1|1,preRowStk<<1,1,0,p+1); //第2种状况 dfs(t,curRowStk<<1|1,preRowStk<<1,1,1,p+1); //第4种状况 dfs(t,curRowStk<<1 ,preRowStk<<1,0,0,p+1); //第7种状况 return ; } if (b1==1 && b2==0)// 1 { // 1 1 dfs(t,curRowStk<<1|1,preRowStk<<1 ,1,1,p+1); //第5种状况 dfs(t,curRowStk<<1|1,preRowStk<<1|1,0,0,p+1); //第7种状况 return ; } // 1 1 // 1 1 dfs(t,curRowStk<<1|1,preRowStk<<1,0,0,p+1); //b1,b2都为1,直接向后推 } int main() { int i; scanf("%I64d %I64d",&n,&m); if (n<m)//交换n,m 使行数大于列数 { n=n^m; m=n^m; n=n^m; } memset(f,0,sizeof(f)); tot=(1<<m)-1; f[0][tot]=1; for (i=1; i<=n; i++) dfs(i,0,0,0,0,1); printf("%I64d\n",f[n][tot]); return 0; }