您的位置:首页 > 其它

SGU131 Hardwood floor

2015-06-14 00:04 369 查看

SGU131 Hardwood floor

题目大意

有一个N*M的矩阵,用1*2的矩形和2*2的L形不重叠无遗漏的覆盖,问有多少种方案

算法思路

状压DP,
f[j][S]
表示填满前j-1列,且第j列的状态为S的方案数

对于第一列,直接判断能否用1*2的矩形覆盖,作为边界条件

对于第j列,需要计算辅助状态
g[S]
,表示第j-1列以及第j列的状态为S的方案数

如果S只有第j-1列,则
g[S] = f[j-1][S]


否则找出第j列最上面的格子,用两种形状的6个状态尝试覆盖,
g[S] = sigma{g[S-Si]}, Si in S


最后,
f[j][S]
对应于
g[S]
中第j-1列填满的状态

时间复杂度: O(M×22N)O(M \times 2^{2N})

代码

/**
* Copyright © 2015 Authors. All rights reserved.
*
* FileName: 131.cpp
* Author: Beiyu Li <sysulby@gmail.com>
* Date: 2015-06-13
*/
#include <bits/stdc++.h>

using namespace std;

#define rep(i,n) for (int i = 0; i < (n); ++i)
#define For(i,s,t) for (int i = (s); i <= (t); ++i)
#define foreach(i,c) for (__typeof(c.begin()) i = c.begin(); i != c.end(); ++i)

typedef long long LL;
typedef pair<int, int> Pii;

const int inf = 0x3f3f3f3f;
const LL infLL = 0x3f3f3f3f3f3f3f3fLL;

int n, m;
LL f[2][1<<9], g[1<<18];
int sp[6][2] = {{0, 3}, {1, 1}, {1, 3}, {2, 3}, {3, 1}, {3, 2}}, s[6];

LL solve()
{
if (n > m) swap(n, m);
if (n == 1) return ~m & 1;
rep(k,6) s[k] = sp[k][1] << n | sp[k][0];
int o = 0, half = (1 << n) - 1;
For(S,0,half) {
f[o][S] = 1;
rep(i,n) if ((1 << i) & S) {
int k = i + 1;
while (k < n && ((1 << k) & S)) ++k;
if ((k - i) & 1) { f[o][S] = 0; break; }
i = k - 1;
}
}
For(j,1,m-1) {
o ^= 1;
rep(S,1<<(n*2)) {
if (S <= half) { g[S] = f[o^1][S]; continue; }
g[S] = 0;
rep(i,n) if ((1 << (i + n)) & S) {
rep(k,6) if (k < 5 || i) {
int S0 = s[k] << (k < 5? i: i - 1);
if ((S0 & S) == S0) g[S] += g[S^S0];
}
break;
}
}
rep(S,1<<n) f[o][S] = g[S<<n|half];
}
return f[o][(1<<n)-1];
}

int main()
{
scanf("%d%d", &n, &m);
printf("%lld\n", solve());

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: