题目链接:https://vjudge.net/problem/POJ-2411
题意:给出n*m的棋盘格,要求用1*2或2*1的长方形完全覆盖,求方案数
并没有想出来这题,于是看了进阶指南。书上的状态设计的很巧妙:设f[i][s]表示到第i行,且第i行的状态为s的方案数。这儿s的某一位为1,表示它是2x1的上半部分;为0则是下半部分,或者1x2的某一格。那么有f[i][s]+=f[i-1][s2],此处s2表示上一行的状态。其中要保证:
1)s&s2==0,因为不能上下两格都是2x1的上半部分
2)s|s2这个状态中,不存在两个1之间有奇数个0,否则1x2无法摆放。
初始化为f[0][0]=1,最后答案为f[n][0],某个状态是否有奇数个连续0,可以预处理得到
#include<iostream> #include<cstring> #define ll long long using namespace std; int a[(1<<12)],b[12],n,m,i,j,s,s2; ll f[12][(1<<12)]; int main(){ while (cin>>n>>m){ if (n==0) break; memset(b,0,sizeof(b)); memset(f,0,sizeof(f)); memset(a,0,sizeof(a)); b[m]=1; for (s=0;s<(1<<m);s++){ for (i=0;i<m;i++) b[i]=s&(1<<i); j=0; int flag=0; while (j<=m){ int num=0; while (!b[j]) {j++; num++;} if (num%2) { flag=1; break; } j++; } if (!flag) a[s]=1; } f[0][0]=1; //* for (i=1;i<=n;i++) for (s=0;s<(1<<m);s++) for (s2=0;s2<(1<<m);s2++) if ((s&s2)==0&&a[s2|s]) //* f[i][s]+=f[i-1][s2]; cout<<f[n][0]<<endl; } return 0; }