AcWing 291. 蒙德里安的梦想(状态压缩DP)

Posted MangataTS

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了AcWing 291. 蒙德里安的梦想(状态压缩DP)相关的知识,希望对你有一定的参考价值。

题目链接

https://www.acwing.com/problem/content/293/

思路

我们用一个n位二进制表示一列的情况,那么一列的情况有 2 n 2^n 2n种,我们枚举塞 1 × 2 1\\times 2 1×2的方块数量,那么最后塞入 2 × 1 2 \\times 1 2×1的方块的数量也是固定了的,我们定义 f [ i ] [ j ] f[i][j] f[i][j]表示已经将前 i − 1 i-1 i1列摆好,且从第 i − 1 i−1 i1列,伸出到第 i i i列的状态是 j j j的所有方案,我们枚举当前第 i i i列的情况时,我们应该是从 i − 1 i-1 i1列的且列状态为满足条件的k状态转移过来即:
f [ i ] [ j ] + = f [ i − 1 ] [ k ] f[i][j] += f[i-1][k] f[i][j]+=f[i1][k],对于每一种状态是否合法,我们可以提前预处理出来不用临时计算

更详细的思路请参见:https://www.acwing.com/solution/content/28088/

代码

#include<bits/stdc++.h>
using namespace std;

#define ll long long
const int N = 12,M = (1<<11) + 5;

ll n,m,f[N][M];
bool st[M];
vector<int> state[M];

void dp()
	memset(f,0,sizeof f);
	memset(st,0,sizeof st);
	for(int i = 0;i < (1<<n); ++i)
		int cnt = 0;
		bool fg = true;
		for(int j = 0;j < n; ++j)
			if((i >> j) & 1)
				if(cnt % 2)
					fg = false;
					break;
				
				cnt = 0;
			else 
				cnt++;
			
		
		if(cnt & 1) fg = false;
		st[i] = fg;
	     
	for(int i = 0;i < (1 << n); ++i) 
		state[i].clear();
		for(int j = 0;j < (1 << n); ++j)
			if(!(i & j) && st[i | j]) state[i].push_back(j);
	
	f[0][0] = 1LL;
	for(int i = 1;i <= m; ++i)
		for(int j = 0;j < (1 << n); ++j)
			for(auto k : state[j]) 
				f[i][j] += f[i-1][k];
	cout<<f[m][0]<<endl;


int main()

	while(cin>>n>>m,n,m)
		dp();
	
	return 0;

以上是关于AcWing 291. 蒙德里安的梦想(状态压缩DP)的主要内容,如果未能解决你的问题,请参考以下文章

AcWing 291. 蒙德里安的梦想(状态压缩DP)

AcWing 291.蒙德里安的梦想

AcWing 291. 蒙德里安的梦想

状压DP蒙德里安的梦想

15.蒙德里安的梦想 状态压缩DP

DP问题从入门到精通4(状态压缩dp,蒙德里安,最短Hamilton路径)