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
i−1列摆好,且从第
i
−
1
i−1
i−1列,伸出到第
i
i
i列的状态是
j
j
j的所有方案,我们枚举当前第
i
i
i列的情况时,我们应该是从
i
−
1
i-1
i−1列的且列状态为满足条件的k状态转移过来即:
f
[
i
]
[
j
]
+
=
f
[
i
−
1
]
[
k
]
f[i][j] += f[i-1][k]
f[i][j]+=f[i−1][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)的主要内容,如果未能解决你的问题,请参考以下文章