Mondriaan’s Dream
轉自 http://www.cnblogs.com/scau20110726/archive/2013/03/14/2960448.html
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <queue>
#include <set>
#include <map>
#include <algorithm>
#include <math.h>
#include <vector>
using namespace std;
typedef long long ll;
const int mod=1e9+7;
const int maxn=1e5+10;
int n,m;
ll dp[15][1<<12];
bool judge(int x){
for (int i=0;i<m;){
if (x&(1<<i)){
if (i==m-1)return false;
if (x&(1<<(i+1)))i+=2;
else return false;
}
else i++;
}
return true;
}
bool OK(int now,int pre){
for (int i=0;i<m;){
if ((now&(1<<i))){//第i行第j列爲1
if (pre&(1<<i)){//第i-1行第j列也爲1,那麼第i行必然是橫放
//第i行和第i-1行的第j+1都必須是1,否則是非法的
if (i==m-1)return false;
if ((now&(1<<(i+1)))==0)return false;
if ((pre&(1<<(i+1)))==0)return false;
i+=2;
}else {
i++;//第i-1行第j列爲0,說明第i行第j列是豎放
}
}else {//第i行第j列爲0,那麼第i-1行的第j列應該是已經填充了的
if (pre&(1<<i)) i++;//已經填充
else return false;
}
}
return true;
}
int main()
{
while (scanf ("%d%d",&n,&m)&&n&&m){
if ((n&1)&&(m&1)){
printf ("0\n");
continue;
}
if (n<m)swap(n,m);//交換後n是行m是列,m較小,那麼狀態數也可以相應減少
memset (dp,0,sizeof (dp));
for(int i=0;i<(1<<m);i++){//枚舉第一行所有可能的狀態
if (judge(i)){
dp[1][i]=1;
}
}
for (int i=2;i<=n;i++){
for (int j=0;j<(1<<m);j++){
for (int k=0;k<(1<<m);k++){
if (OK(j,k)){
dp[i][j]+=dp[i-1][k];
}
}
}
}
printf ("%lld\n",dp[n][(1<<m)-1]);
}
return 0;
}