先贴个连接: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;
}