题目链接:http://acm.sgu.ru/problem.php?contest=0&problem=131
题意:给出n*m(1≤n、m≤9)的方格棋盘,用1*2 的矩形的骨牌和L 形的(2*2 的去掉一个角)骨牌不重叠地覆盖,求覆盖满的方案数。
分析:覆盖模型,状态压缩DP。具体见周伟《状态压缩》。
Code:
#include <algorithm> #include <iostream> #include <cstring> #include <string> #include <cstdio> #include <vector> #include <queue> #include <cmath> #include <map> #include <set> #define LL long long #define Max(a,b) ((a)>(b)?(a):(b)) #define Min(a,b) ((a)<(b)?(a):(b)) using namespace std; const int inf=0x3f3f3f3f; LL dp[2][1000]; int n,m,t; void dfs(int s1,int s2,int b1,int b2,int cnt){ if(cnt>=m){ if(!b1&&!b2) dp[t][s1]+=dp[t^1][s2]; return ; } if(b1==0){ dfs((s1<<1)|1,(s2<<1)+1-b2,1,0,cnt+1); dfs((s1<<1)|1,(s2<<1)+1-b2,1,1,cnt+1); if(b2==0){ dfs((s1<<1)|1,s2<<1,0,0,cnt+1); dfs((s1<<1)|1,s2<<1,1,0,cnt+1); dfs((s1<<1)|1,s2<<1,0,1,cnt+1); } } if(b2==0) dfs((s1<<1)+b1,s2<<1,1,1,cnt+1); dfs((s1<<1)+b1,(s2<<1)+1-b2,0,0,cnt+1); } int main() { while(scanf("%d %d",&n,&m)==2){ memset(dp,0,sizeof(dp)); if(n<m){n^=m;m^=n;n^=m;} dp[0][(1<<m)-1]=1; t=0; for(int i=1;i<=n;i++){ t^=1; memset(dp[t],0,sizeof(dp[0])); dfs(0,0,0,0,0); } cout<<dp[t][(1<<m)-1]<<endl; } return 0; }