先贴个连接:http://www.nocow.cn/index.php/Sgu/131 参考了NOCOW的题解...
题意是要铺满N*M的区域,现在有1*2和2*2挖掉一个角 (都允许旋转)两种地砖,问共有多少种铺法..
每次转移共有六种方案
/*
## #. ## ## #. .#
.. #. #. .# ## ##
1 2 3 4 5 6
*/
由于最大只有9*9,每行可以压缩一下来存储状态,并且第i行的状态不会影响i+2行以后的状态,所以可以用f[i]表示当前行达到状态i的方案数,g[i]表示当前行铺满时,对下一行产生的影响为i的方案数,然后两个数组来回滚几次地推一下,就ok了。答案很大,注意用long long。
/* ## #. ## ## #. .# .. #. #. .# ## ## 1 2 3 4 5 6 */ #include <cstdio> #include <iostream> #include <algorithm> #include <cmath> #include <string> #include <cstring> #define bin(i) 1<<i #define emp(a,i) (!(a & bin(i))) using namespace std; typedef long long ll; const int maxn=(1<<11); int n,m; int full; ll g[maxn],f[maxn]; void dfs(int a,int b,ll kk) { if (a==full) { g[b]+=kk; return ; } for(int i=0; i<m; i++) { if (emp(a,i)) { if (i+1<m && emp(a,i+1)) { dfs(a|bin(i)|bin(i+1),b,kk); // #1 if (emp(b,i)) dfs(a|bin(i)|bin(i+1),b|bin(i),kk); // #3 if (emp(b,i+1)) dfs(a|bin(i)|bin(i+1),b|bin(i+1),kk); //#4 } if (emp(b,i)) { dfs(a|bin(i),b|bin(i),kk); // #2 if (i+1<m && emp(b,i+1)) { dfs(a|bin(i),b|bin(i)|bin(i+1),kk); // #5 } if (i>0 && emp(b,i-1)) { dfs(a|bin(i),b|bin(i)|bin(i-1),kk); // #6 } } break; } } } int main() { // freopen("in.txt","r",stdin); scanf("%d%d",&n,&m); full=(1<<m)-1; memset(f,0,sizeof f); memset(g,0,sizeof g); f[full]=1; for (int k=0; k<=n; k++) { for (int i=0; i<=full; i++) if (f[i]) dfs(i,0,f[i]); memcpy(f,g,sizeof g); memset(g,0,sizeof g); } cout<<f[0]<<endl; return 0; }