Description
Expert as he was in this material, he saw at a glance that he’ll need a computer to calculate the number of ways to fill the large rectangle whose dimensions were integer values, as well. Help him, so that his dream won’t turn into a nightmare!
Input
Output
For each test case, output the number of different ways the given rectangle can be filled with small rectangles of size 2 times 1. Assume the given large rectangle is oriented, i.e. count symmetrical tilings multiple times.
Sample Input
1 2 1 3 1 4 2 2 2 3 2 4 2 11 4 11 0 0
Sample Output
1 0 1 2 3 5 144 51205
Source
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
状压DP~
状态的记录方式:对于横放,两个格子都为1,对于竖放,上一个格子为0,下一个格子为1,这样可以方便地判断上下两行的状态是否符合要求。
用f[i][k]表示状态k时,第i行的种类数,通过枚举i-1行的情况来更新,主要就是判断上一行和这一行是否符合。
判断方式:
分为第一行和其余所有行,第一行判断是否有连续的奇数个0,如果有,就不符合情况。
其余所有行,假设判断到i行的j位,若[i][j]=0且上一行j位也为0,则不符合;如果[i][j]=0且上一行j位为1,则这一位符合,i++;
若[i][j]=1且上一行j为0,则这一位符合,i++;若[i][j]=1且上一行j为1,则表示这一行j+1位必为1,如果不是,就不符合;如果是,再分类讨论i-1行j+1位是否为1,如果不是1,则也不符合;如果是1,则i直接加2。
(限于语言表达能力,没看懂上面一段的还请看代码QAQ)
最后一行肯定是全是1,所以直接用(1<<m)-1来判断,更新ans即可,不用从0循环到(1<<m)-1,可以大大减少搜索时间。
但是为什么交换nm结果就错了啊……好奇怪啊……
(这道题也能用插头DP做,16ms,详见
http://blog.csdn.net/senyelicone/article/details/56830274
)
#include<cstdio>
#include<cstring>
#include<iostream>
using namespace std;
#define ll long long
int n,m,tot;
ll f[11][2050],ans;
bool chec(int u,int uv,int vv)
{
if(u==1)
{
int i=0;
while(i<m)
{
if(!(uv&(1<<i))) i++;
else if(i==m-1 || !(uv&(1<<(i+1)))) return 0;
else i+=2;
}
return 1;
}
int i=0;
while(i<m)
{
if(!(uv&(1<<i)))
{
if(!(vv&(1<<i))) return 0;
i++;
}
else if(!(vv&(1<<i))) i++;
else if(i==m-1 || !((uv&(1<<(i+1))) && (vv&(1<<(i+1))))) return 0;
else i+=2;
}
return 1;
}
int main()
{
while(scanf("%d%d",&n,&m)==2 && n)
{
if((n*m)%2)
{
printf("0\n");continue;
}
if(n==1)
{
printf("1\n");continue;
}
memset(f,0,sizeof(f));ans=0;tot=(1<<m)-1;
for(int i=0;i<=tot;i++) if(chec(1,i,0)) f[1][i]=1;
for(int i=2;i<n;i++)
for(int k=0;k<=tot;k++)
for(int j=0;j<=tot;j++)
if(f[i-1][j] && chec(i,k,j)) f[i][k]+=f[i-1][j];
for(int i=0;i<=tot;i++) if(chec(n,tot,i)) ans+=f[n-1][i];
printf("%lld\n",ans);
}
return 0;
}