【狀壓DP+高精】【cofun1370】走道鋪磚問題

【cofun1370】走道鋪磚問題

Description
有一個專門爲裝修設計方案的設計師。在某一天,他接到了一個項目,爲一棟正在修建的大樓設計走道的地板鋪設方案。此項目的委託人事先便進行了說明:地板磚只有1×2一種規格,而整棟樓中同類走道又有許多個,他不想其中有任何的兩個出現重複的設計方案。因此,設計師必須確定其可行性,即對於一個N×M(N×M爲偶數)的走道,用N×M/2塊1×2的地板磚將其鋪滿,可以有多少種不同的設計方案,如果方案總數少於此類走道的個數,則該項目邊不可能實現。
現在,他需要這樣一個程序:對於輸入的走道規格N、M,計算出可以設計出的不同方案總數(不要求本質不同)。

Input Format
輸入文件僅一行,有兩個數N、M,表示走道的規格。
Output Format
輸出文件也只有一行,即得出的方案總數。

Sample Input
3 4
Sample Output
11

Hint
由於是走道,所以N和M中將會有一個較小。其中min{N,M}≤12,1≤N、M≤40,且N×M爲偶數。


  • 分析 :
    • min{N, M} <= 12, 因此考慮狀壓DP。
      這題不是棋盤問題了,而是覆蓋問題。
      但我們可以用類似的思想考慮:
      ①由於搬磚1 * 2,當前行僅與上一行相關聯。
      ②dfs出每行的覆蓋情況,把當前行和上一行壓成二進制分別存在數組t,g中。(0:未覆蓋/ 1:已覆蓋)
      ③枚舉每行進行狀壓DP,轉移方程:
    f[i][t[j]] = f[i][t[j]] + f[i - 1][g[j]];

f[i][t[j]]:到了第i行,當前行狀態爲t[j]。

注意:由於數據大,需要運用高精度。
【這題的dfs轉移本po理解了好久PUP代碼中有一丟丟註解ヽ( ̄▽ ̄)ノ


  • 代碼:
#include <cstdio>
#include <algorithm>
#include <iostream>
#include <cstring>
#include <cmath>
#include <queue>
#include <set>
#include <map>
 using namespace std;

 int n, m, i, j, k, l, p, d, ans, t[50000], g[50000], f[50][5000][75];

 void dfs(int q,int x,int y) {
        if (q > m) return;
        if (q == m) {
            d ++;
            t[d] = x;
            g[d] = y;
            return;
        }

        dfs(q + 1, (x << 1) + 1,y << 1);//豎放
        dfs(q + 2, (x << 2) + 3,(y << 2) + 3);//橫放
        dfs(q + 1, x << 1, (y << 1) + 1);//不放
        return;
 }//x:當前行的當前狀態;y:上一行的當前狀態,這裏經過放置後上一行一定要是滿的,po主糊了好久在轉移爲啥不是(y << 1) + 1, (y << 2) + 3, y << 1, 就是因爲不理解y是在放之前的=a=

 int main(){
        scanf("%d%d", &n, &m);
        if (n < m) {i = n; n = m; m = i;}
        //讀入 
        d = 0;
        dfs(0, 0, 0);
        //搜索出每行和上一行的情況 
        memset(f, 0, sizeof(f));
        f[0][(1 << m) - 1][0] = 1;
        f[0][(1 << m) - 1][1] = 1;
        //初始化 
        for(i = 1; i <= n; i ++) {
            for(j = 1; j <= d; j ++) {
                p = 0;
                l = max(f[i][t[j]][0], f[i-1][g[j]][0]);
                for(k = 1; k <= l; k ++) {
                    f[i][t[j]][k] = f[i][t[j]][k]+p+f[i-1][g[j]][k];
                    p = f[i][t[j]][k]/10;
                    f[i][t[j]][k] %= 10;
                }   
                f[i][t[j]][0] = l;

                while (p > 0) {
                    f[i][t[j]][0] ++;
                    f[i][t[j]][f[i][t[j]][0]] = p % 10;
                    p /= 10;
                }
            }
        }
        //狀壓DP 
        for(i = f[n][(1 << m)-1][0]; i >= 1; i --)
            printf("%d",f[n][(1 << m)-1][i]);
        //高精度數輸出 
 }

*另一題是本題的多組數據&答案弱化版,題目大意一致,可以不用高精度,但是沒有保證n,m都是偶數,要一個判斷,一起放在這。→
【cofun1371】 Mondriaan’s Dream


打完上一篇已經道了晚安,可是一想到狀壓題還有好幾道= =趁着清醒再碼一題ORZ
真的睡覺啦~ 晚安:-)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章