SGU131 Hardwood floor

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)

代码

/** * Copyright © 2015 Authors. All rights reserved. * * FileName: 131.cpp * Author: Beiyu Li <[email protected]> * 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;
}

你可能感兴趣的:(dp,sgu)