题意:给出一个N*M的矩形盒子,往里面放入1*2大小的长方形蛋糕,问将这个盒子填满有多少种放法
分析:这还是一个通过记录搜索结果来进一步枚举状态的题,我们通过从上往下搜索每一行,从左往右搜索每一格,每次的状态定义为当前行和下一行的放置情况,若当前格子放有蛋糕,则标记为1,否则为0,所以每次枚举的状态是一个长度为2*M的二进制串,从低位到高位数,前M个位置为当前行,后M个位置为下一行。所以我们假设一个记录数组为DP[S]表示在放置某行某格时当前行和下一行状态为S时的方法数。
转移方程:若在某次枚举状态 S0 中,当前行 i 的当前格 j 没有放置蛋糕,那么肯定可以竖着放下一个蛋糕,同时放置完这个蛋糕后的状态 S1 的数组 DP[S1]+=DP[S0] , 然后我们判断一下当前位置能否横着放下一个蛋糕,条件是 j+1格处为 0 且 j格不在这一行的最后一格,若满足则放置完这个蛋糕后的状态 S2 的数组 DP[S2]+=DP[S0]
每次枚举完一行,我们需要还需要统计一下满足条件的状态数组,将它转移到下一行里去。即这些 S 有没有将当前行都放置满蛋糕(二进制串从右往左的M位是否都是1),若满足这个条件,则 DP[S′]=DP[S] (S′=(S>>M))
最开始,我们需要把DP[0]设置为1,最后整个盒子放置满的方法数就是S为当前行全是1,下一行全是0的状态下数组里记录的结果了
AC代码:
/*************************************************************************
> File Name: test.cpp
> Author: Akira
> Mail: qaq.febr2.qaq@gmail.com
************************************************************************/
#include <iostream>
#include <cstdio>
#include <cstring>
#include <string>
#include <cstdlib>
#include <algorithm>
#include <queue>
#include <stack>
#include <map>
#include <cmath>
#include <vector>
#include <set>
#include <list>
#include <ctime>
typedef long long LL;
typedef unsigned long long ULL;
typedef long double LD;
#define MST(a,b) memset(a,b,sizeof(a))
#define CLR(a) MST(a,0)
#define Sqr(a) ((a)*(a))
using namespace std;
#define MaxN 100000
#define MaxM MaxN*10
#define INF 0x3f3f3f3f
#define bug cout<<88888888<<endl;
#define MIN(x,y) (x<y?x:y)
#define MAX(x,y) (x>y?x:y)
const int MOD = 1000000007;
template<typename _> inline void scan(_& t)
{
int c;
while((c = getchar()) < '0' || c > '9');
t = c - '0';
while((c = getchar()) >= '0' && c <= '9') t = t * 10 + c - '0';
}
template<typename _> inline void print(_ x)
{
int len = 0, p[20];
if(x < 0) putchar('-'), x = -x;
while(x) p[++len] = x % 10, x /= 10;
if(!len) p[++len] = 0;
while(len) putchar(p[len--] + '0');
}
int N, M;
int DP[2][(1<<10)+1];
void solve()
{
int l = (1<<M)-1;
int len = 1 << (2*M);
DP[0][0] = 1;
int flag = 0;
for(int i=0;i<N;i++)
{
CLR(DP[flag^1]);
for(int j=0;j<M;j++)
{
for(int s=0;s<len;s++)
{
if( ((1<<j)&s)==0 )
{
if( j!=M-1 && ((1<<(j+1))&s)==0 )
DP[flag][s|(1<<j)|(1<<(j+1))] = (DP[flag][s|(1<<j)|(1<<(j+1))] + DP[flag][s])%MOD;
DP[flag][s|(1<<(j+M))|(1<<j)] = (DP[flag][s|(1<<(j+M))|(1<<j)] + DP[flag][s])%MOD;
}
}
}
for(int s=0;s<len;s++)
if( (s&l) == l )
DP[flag^1][s>>M]=DP[flag][s];
flag^=1;
}
print(DP[flag^1][l]);
cout << endl;
}
int main()
{
scan(N);scan(M);
solve();
system("pause");
}