【poj2411】Mondriaan's Dream 状态压缩dp

AC传送门:http://vjudge.net/problem/POJ-2411

【题目大意】

有一个W行H列的广场,需要用1*2小砖铺盖,小砖之间互相不能重叠,问有多少种不同的铺法?

【题解】

对于每一行有w个位置,所以每一行都有0~2w-1种状态。

对于当前行的状态s,它是由前一行的状态s’转化过来的,显然,对于该行某个位置j:

如果前一行该位置为0,那么该位置可以竖放 即 0-> 1

如果前一行连续两个位置为0,那么这两个连续位置可以横放 即00-> 00

如果前一行该位置为1,显然该位置不能再放,于是应该把该位置设置为0 ,即1-> 0

/*************
  poj 2411
  by chty
  2016.11.15
*************/
#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<ctime>
#include<cmath>
#include<algorithm>
using namespace std;
#define FILE "read"
#define up(i,j,n)  for(int i=j;i<=n;i++)
namespace INIT{
	char buf[1<<15],*fs,*ft;
	inline char getc() {return (fs==ft&&(ft=(fs=buf)+fread(buf,1,1<<15,stdin),fs==ft))?0:*fs++;}
	inline int read(){
		int x=0,f=1;  char ch=getc();
		while(!isdigit(ch))  {if(ch=='-')  f=-1;  ch=getc();}
		while(isdigit(ch))  {x=x*10+ch-'0';  ch=getc();}
		return x*f;
	}
}using namespace INIT;
int n,m;
long long f[15][2500];
void dfs(int i,int s1,int s2,int next){
	if(next>m)  return;
	if(next==m)  f[i+1][s2]+=f[i][s1];
	else if((s2&(1<<next))==0){
		dfs(i,s1,s2|(1<<next),next+1);
		if((s2&(1<<(next+1)))==0)  dfs(i,s1,s2,next+2);
	}
	else dfs(i,s1,s2&~(1<<next),next+1);
}
int main(){
	freopen(FILE".in","r",stdin);
	freopen(FILE".out","w",stdout);
	while(~scanf("%d%d",&n,&m)&&n&&m){
		memset(f,0,sizeof(f));  f[1][0]=1;
		up(i,1,n)  up(j,0,(1<<m)-1)  if(f[i][j])  dfs(i,j,j,0);
		printf("%lld\n",f[n+1][0]);
	}
	return 0;
}


posted @ 2016-11-15 18:56  chty  阅读(178)  评论(0编辑  收藏  举报