题目链接:http://poj.org/problem?id=2411
题意:由1*2 的矩形通过组合拼成大矩形,求拼成指定的大矩形有几种拼法。
分析:如果是横着的就定义11,如果竖着的定义为竖着的01,状态兼容时只需考虑两种情况,当前行|上一行,是不是全为1,不是说明竖着有空(不能出现竖着的00),然后再当前行&上一行,这里被消掉的1全部用来竖着放的,判断之后的状态是否有奇数的连续1,有则不能转移的,因为剩下的都是用来行着放了。
#include <cstdio> #include <cstring> #include <string> #include <cmath> #include <iostream> #include <algorithm> #include <queue> #include <cstdlib> #include <stack> #include <vector> #include <set> #include <map> #define LL long long #define mod 100000000 #define inf 0x3f3f3f3f #define eps 1e-9 #define N 100010 #define FILL(a,b) (memset(a,b,sizeof(a))) #define lson l,m,rt<<1 #define rson m+1,r,rt<<1|1 using namespace std; LL dp[15][1<<12]; int fit[1<<12]; int tot,n,m; bool ok(int x)//判断一行状态中是否有奇数的连续1 { int opp=0; while(x) { if(x&1)opp++; else { if(opp&1)return 0; opp=0; } x>>=1; } return (opp&1)==0; } bool judge(int j,int k) { if((j|k)!=(1<<m)-1)return false; return fit[j&k]; } int main() { for(int i=0;i<(1<<11);i++)if(ok(i))fit[i]=1; while(scanf("%d%d",&n,&m)>0) { if(n+m==0)break; FILL(dp,0); if(m*n&1) { puts("0");continue; } if(n<m)swap(n,m); for(int i=0;i<(1<<m);i++) dp[1][i]=fit[i]; for(int i=2;i<=n;i++) { for(int j=0;j<(1<<m);j++) for(int k=0;k<(1<<m);k++) if(judge(j,k)) dp[i][j]+=dp[i-1][k]; } printf("%lld ",dp[n][(1<<m)-1]); } }