poj2411 Mondriaan's Dream
题目链接:https://vjudge.net/problem/POJ-2411
题意:给出n*m的棋盘格,要求用1*2或2*1的长方形完全覆盖,求方案数
并没有想出来这题,于是看了进阶指南。书上的状态设计的很巧妙:设f[i][s]表示到第i行,且第i行的状态为s的方案数。这儿s的某一位为1,表示它是2x1的上半部分;为0则是下半部分,或者1x2的某一格。那么有f[i][s]+=f[i-1][s2],此处s2表示上一行的状态。其中要保证:
1)s&s2==0,因为不能上下两格都是2x1的上半部分
2)s|s2这个状态中,不存在两个1之间有奇数个0,否则1x2无法摆放。
初始化为f[0][0]=1,最后答案为f[n][0],某个状态是否有奇数个连续0,可以预处理得到
#include<iostream>
#include<cstring>
#define ll long long
using namespace std;
int a[(1<<12)],b[12],n,m,i,j,s,s2;
ll f[12][(1<<12)];
int main(){
while (cin>>n>>m){
if (n==0) break;
memset(b,0,sizeof(b));
memset(f,0,sizeof(f));
memset(a,0,sizeof(a));
b[m]=1;
for (s=0;s<(1<<m);s++){
for (i=0;i<m;i++) b[i]=s&(1<<i);
j=0; int flag=0;
while (j<=m){
int num=0;
while (!b[j]) {j++; num++;}
if (num%2) {
flag=1; break;
}
j++;
}
if (!flag) a[s]=1;
}
f[0][0]=1; //*
for (i=1;i<=n;i++)
for (s=0;s<(1<<m);s++)
for (s2=0;s2<(1<<m);s2++)
if ((s&s2)==0&&a[s2|s]) //*
f[i][s]+=f[i-1][s2];
cout<<f[n][0]<<endl;
}
return 0;
}

浙公网安备 33010602011771号