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;
}

 

  

 

posted @ 2020-09-14 16:18  coastal_taipan  阅读(142)  评论(0)    收藏  举报