首先注意:最后结果的大小可能超过int型,本人wa了2次,然后也没什么需要注意的了,在想状态转移方程的时候,千万别把当前列和上一列的情况弄混淆了,代码里有注释。
第一种方法:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#define max(a1,b1) (a1)>(b1)?(a1):(b1)
using namespace std;
int r,c;
bool sta[2100];
long long dp[12][2100];
bool judge(int x)
{
int tmp = 0;
while(x>0)
{
if(x&1)
{
tmp++;
}
else if(tmp&1)
{
return false;
}
x >>= 1;
}
if(tmp&1)
return false;
return true;
}
int main(void)
{
int kk = 1<<11;
for(int i=0;i<kk;++i)
if(judge(i)) sta[i] = true;
else sta[i] = false;
while(cin>>r>>c,r||c)
{
int k;
if(r*c%2)//总的格子数为奇数个
{
cout<<"0"<<endl;
continue;
}
k = (1<<r)-1;
memset(dp,0,sizeof(dp));
for(int i=0;i<=k;++i)
if(sta[i])
dp[1][i] = 1;
for(int i=2;i<=c;++i)
for(int j=0;j<=k;++j)//j为上一列的情况
for(int e=0;e<=k;++e)//下一列需要平铺的情况(竖着放的需要按照上一行来确定)
{
if((e^(k)|j)!=k) continue;//竖着放的地方与横着放的地方重叠
int tmp = (k^j)|e;
if(!sta[e]) continue;//
dp[i][tmp] += dp[i-1][j];
}
cout<<dp[c][k]<<endl;
}
return 0;
}
第二种方法:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#define max(a1,b1) (a1)>(b1)?(a1):(b1)
using namespace std;
int r,c;
bool sta[2100];
long long dp[12][2100];
bool judge(int x)
{
int tmp = 0;
while(x>0)
{
if(x&1)
{
tmp++;
}
else if(tmp&1)
{
return false;
}
x >>= 1;
}
if(tmp&1)
return false;
return true;
}
int main(void)
{
int kk = 1<<11;
for(int i=0;i<kk;++i)
if(judge(i)) sta[i] = true;
else sta[i] = false;
while(cin>>r>>c,r||c)
{
int k;
if(r*c%2)//总的格子数为奇数个
{
cout<<"0"<<endl;
continue;
}
k = (1<<r)-1;
memset(dp,0,sizeof(dp));
for(int i=0;i<=k;++i)
if(sta[i])
dp[1][i] = 1;
for(int i=2;i<=c;++i)
for(int j=0;j<=k;++j)//j为上一列的情况
for(int e=0;e<=k;++e)//直接枚举当前列的状态
{
int tmp = j^k;
if((tmp&e)!=tmp)//上一列空的地方在当前列必须为满
continue;
int flag = tmp^e;//除去为填补上一列,剩下的就是当前列需要平铺的
if(sta[flag])
dp[i][e] += dp[i-1][j];
}
cout<<dp[c][k]<<endl;
}
return 0;
}