其他分享
首页 > 其他分享> > poj 2411 Mondriaan‘s Dream

poj 2411 Mondriaan‘s Dream

作者:互联网

题目传送门:

2411 – Mondriaan’s Dream (poj.org)

OpenJudge - 1413:Mondriaan’s Dream

这题一上来看数据范围就知道了,不是搜索就是状压 dp ,再加上多组数据,肯定就是状压 dp ,很容易想到 f [ i ] [ j ] f[i][j] f[i][j] 表示第 i 行状态为 j 时的方案数,因为每一行的状态都只和,接下来就是确定 j

因为每一个格子不是被横的方块覆盖就是被竖着的方块铺着,所以很容易想到 j 的 i 位表示是否是被横着铺的,但是我们发现这样没有办法转移,因为我们没法确定上一行的竖着的砖头是向上还是向下延伸的,于是我们给这个竖着的砖头一个标记,对于一个竖着的砖头,上面的标 0 ,下面标 1 ,即:

0
1

那么状态转移就简单了, f [ i ] [ j ] = ∑ f [ i − 1 ] [ k ] f[i][j]=\sum f[i-1][k] f[i][j]=∑f[i−1][k] 其中 k k k 代表这一行状态为 j j j 时上一行的所有可能的状态,答案更简单,就是 f [ n ] [ 2 m − 1 ] f[n][2^m-1] f[n][2m−1],初始状态非常简单,第一行一定没有竖砖块的下端,于是剩下的 1 都是横砖块,dfs 一下就好

这题的重点其实在确定 k k k ,我们可以列出表格:

k 的 i 位j 的 i 位正确?
00×
01
10
11

我们把除了 1 1 的三种情况中 j 的 1 清零,那么剩下的都是横砖,和第一行的状态一样,不用再计算一遍,代码:

#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define rp(i, e) for(int i=1;i<=(e);i++)
#define pr(i, e) for(int i=(e);i>=1;i--)
#define rp0(i, e) for(int i=0;i<(e);i++)
#define pr0(i, e) for(int i=(e)-1;i>=0;i--)
#define rps(i, b, e) for(int i=(b);i<=(e);i++)
#define prs(i, e, b) for(int i=(e);i>=(b);i--)
#define rpg(i, x) for(int i=head[x];i;i=e[i].nxt)
using namespace std;
const int NR=13;
typedef long long LL;
int n, m;
LL f[NR][1<<NR];
inline bool jud(int x, int y)
{
	bool a, b;
	rp0(i, m)
	{
		a=x>>i&1, b=y>>i&1;
		if(a+b==0)return false;
		if(!a && b)y&=(1<<m)-1-(1<<i);
	}
	return f[1][y];
}
void idfs(int step, int sta)
{
	if(step>m)
	{
		f[1][sta]=1;
		return;
	}
	idfs(step+1, sta<<1);
	if(step<m)idfs(step+2, sta<<2|3);
}
int main()
{
	while(true)
	{
		scanf("%d%d", &n, &m);
		if(!n && !m)break;
		if(n*m%2)
		{
			puts("0");
			continue;
		}
		if(n<m)swap(n, m);
		memset(f, 0, sizeof(f));
		idfs(1, 0);
		rps(i, 2, n)
			rp0(j, 1<<m)
				rp0(k, 1<<m)
					f[i][j]+=jud(k, j)*f[i-1][k];
		printf("%lld\n", f[n][(1<<m)-1]);
	}
	return 0;
}

标签:int,Mondriaan,2411,--,include,Dream,define
来源: https://blog.csdn.net/m0_59024001/article/details/118342544