蒙德里安的梦想

蒙德里安的梦想

如果横的放置确定了,那么纵向的肯定也确定了。所以只需要计算横着的方案数即可。
考虑使用 \(f[i][j]\) 表示当前已经处理到了第 \(i\) 列,状态为 \(j\)(状态表示这一列的每个位置是否被长方形占据了)。然后转移的话可以从上一列的许多状态中转移,但是需要满足两个条件

  • 保证当前状态和上一列的状态的交集为空,为什么呢?如果这个状态某个位置有,那就说明这个位置的前一列延伸出一个长方形,同理前一列的前一列也延伸出一个,就重叠了。
  • 二者的并集(就是第 \(i-1\) 列所有被占据的格子)中不能有连续奇数个 \(0\),这比较好理解,如果有,那么就不能使用纵向小方格填补空白了。
#include<bits/stdc++.h>
using namespace std;
const int N=12;
int n,m;
long long f[N][1<<N];
bool st[1<<N];
int main(){
	while(scanf("%d%d",&n,&m),n|m){
		memset(f,0,sizeof f);
		for(int i=0;i<1<<n;++i){
			st[i]=1;
			int cnt=0;
			for(int j=0;j<n;++j)
				if(i>>j&1){
					if(cnt&1)st[i]=0;
					cnt=0;
				}
				else ++cnt;
			if(cnt&1)st[i]=0;
		}
		f[0][0]=1;
		for(int i=1;i<=m;++i)
			for(int j=0;j<1<<n;++j)
				for(int k=0;k<1<<n;++k)
					if(!(j&k)&&st[j|k])f[i][j]+=f[i-1][k];
		printf("%lld\n",f[m][0]);
	}
}
posted @ 2023-05-14 16:05  wscqwq  阅读(11)  评论(0编辑  收藏  举报