1. 程式人生 > >UVA11270 Tiling Dominoes

UVA11270 Tiling Dominoes

class 註意 sca pre spa 數據 整數 cto 特殊

\(\color{#0066ff}{ 題目描述 }\)

給定一個m×n的矩形網格,用1×2多米諾骨牌完全平鋪。 請註意,即使一個平鋪的旋轉與另一個平鋪相匹配,它們仍算作不同的平鋪。 下面顯示了一個平鋪示例。 輸入格式

輸入包括多組數據。每組數據占一行,包含兩個整數m,n(n×m≤100)。輸入結束標誌為文件結束符(EOF)。 輸出格式

對於每組數據輸出一行,輸出總數。

\(\color{#0066ff}{輸入格式}\)

每組數據,兩個整數 \(n,m\)

\(\color{#0066ff}{輸出格式}\)

對於每組數據,輸出答案。

\(\color{#0066ff}{輸入樣例}\)

2 10
4 10
8 8

\(\color{#0066ff}{輸出樣例}\)

89
18061
12988816

\(\color{#0066ff}{數據範圍與提示}\)

\(n*m\leq 100\)

\(\color{#0066ff}{ 題解 }\)

一個狀壓DP,也可以寫插頭DP蒟蒻目前還不會

可以發現,行或列其中一個一定不超過10,所以將其狀壓

橫著的塊均為0, 豎著的塊,上面為1, 下面為0

因此,如果上一行的某位置為1,那麽本行該位置必須為0, 代表豎著塊的下半部分

最後一行的狀態必須為0

如何判斷一個狀態能否作為某狀態的下一行

首先,對於橫著的塊,肯定是成對出現的,但是如果上一行是1,那麽對應本行的0是屬於豎著的塊的,是獨立的,不能與旁邊的0拼成橫著的

可以發現,將它們進行按位或,那麽那些特殊的0就成了1, 這時候判斷一下每次連續的0是否有偶數個就行了

對於上面是1下面必須是0的問題,可以按位與一下,為0就行了

為了保證時間復雜度,與處理出合法拼接狀態,就能過了

#include<bits/stdc++.h>
#define LL long long
LL in() {
    char ch; LL x = 0, f = 1;
    while(!isdigit(ch = getchar()))(ch == '-') && (f = -f);
    for(x = ch ^ 48; isdigit(ch = getchar()); x = (x << 1) + (x << 3) + (ch ^ 48));
    return x * f;
}
using std::vector;
LL f[120][2050];
vector<int> v[2050][11];
int n, m;
bool cant(int zt, int lim) {
    int tot = 0;
    for(int i = 0; i < lim; i++) {
        if(zt & (1 << i)) { 
            if(tot & 1) return true;
            tot = 0;
        }
        else tot++;
    }
    if(tot & 1) return true;
    return false;
}
LL dfs(int dep, int zt) {
    if(dep == n) return !zt;
    if(f[dep][zt]) return f[dep][zt];
    for(int i = 0; i < (int)v[zt][m].size(); i++) {
        f[dep][zt] += dfs(dep + 1, v[zt][m][i]);
    }
    return f[dep][zt];
}
bool ok(int zt) {
    for(int i = 1; i < 9; i++) 
        if(!(zt & (1 << i)) && (zt & (1 << (i - 1))) && (zt & (1 << (i + 1)))) return false;
    return true;
}
int main() {
    for(int lim = 1; lim <= 10; lim++)
        for(int i = 0; i < (1 << lim); i++)
            for(int j = 0; j < (1 << lim); j++) {
                if((i & j) || cant(i | j, lim)) continue;
                v[i][lim].push_back(j);
            }
    while(~scanf("%d%d", &n, &m)) {
        if(m > n) std::swap(n, m);
        memset(f, 0, sizeof f);
        if((n * m) & 1) puts("0");
        else printf("%lld\n", m == 1? (n & 1? 0 : 1) : dfs(0, 0));
    }
    return 0;
}

UVA11270 Tiling Dominoes