题意:问用L形和I形装骨牌完全覆盖棋盘的方案数
做法:2进制的优越状态一定要充分利用,理解0,1的作用。在DFS当前行的同时,记录下这种方案对上一行的影响(s2),在每一行的遍历最后对s2取反就是上一行的状态。转移方程为 dp[i][s1]+=dp[i-1][反s2],这里的取反不应该用 "~".
#include<stdio.h> #include<string.h> #define LL long long LL dp[10][530]; int m,n,i,lim;
//若s1,s2的影响多余两列,则不应该直接加上影响,应该一列列的来,遗漏情况就不好了 void dfs(int lie,int s1,int s2,int b1,int b2) { if(lie>=m) { int x=s2^(lim-1); if(!b1&&!b2&&dp[i-1][x]) { dp[i][s1]+=dp[i-1][x]; } return; } dfs(lie+1,s1|b1<<lie,s2|b2<<lie,0,0); if(!b1&&!b2) { dfs(lie+1,s1|1<<lie,s2|1<<lie,0,0); if(lie<m-1) dfs(lie+1,s1|1<<lie,s2|1<<lie,1,0); if(lie<m-1) dfs(lie+1,s1|1<<lie,s2|1<<lie,0,1); } if(!b1&&lie<m-1) { dfs(lie+1,s1|1<<lie,s2|b2<<lie,1,1); dfs(lie+1,s1|1<<lie,s2|b2<<lie,1,0); } if(!b2&&lie<m-1) dfs(lie+1,s1|b1<<lie,s2|1<<lie,1,1); } int main() { int j; while(scanf("%d%d",&m,&n)!=EOF) { lim=1<<m; memset(dp,0,sizeof(dp)); dp[0][lim-1]=1; for(i=1;i<=n;i++) dfs(0,0,0,0,0); printf("%I64d\n",dp[n][lim-1]); } return 0; }