M * N 矩陣的骨牌覆蓋問題

問題描述

有一個 M * N的矩陣,現在需要使用 1 * 2 的骨牌進行覆蓋,問總的覆蓋方案數有多少?
題目鏈接:http://hihocoder.com/contest/hiho43/problem/1

問題求解

  • 標記骨牌覆蓋狀態
    1, 橫向排的骨牌表示:
    1 1
    2, 縱向排的骨牌表示:
    0
    1

  • 骨牌狀態轉移
    對於第 i 行與第 i+1 行,其中某段格子狀態如下:

    • 轉移一
      i: 0
      i+1: 1 // 如果第 i 行的某個格子爲0,那麼第 i+1 行對應的一定是1才行。

    • 轉移二
      i: 1 // 第 i 行的這個格子爲1,有兩種可能:縱向放置骨牌的下面那個;或是橫向放置骨牌的第二個
      i+1: 0 // 不管上面那個格子是如何放置,第i+1行都可以是0,即豎向擺放骨牌的第一個格子。

    • 轉移三
      i: 1 1
      i+1: 1 1 // 第 i 行和第 i+1 行都是橫向排列

那麼由此而來,就有了如下代碼了:

#include <iostream>
#include <cstdio>
#include <cstdlib>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>

#define MAX_K  7
#define STATUS_COUNT (2<<MAX_K)

using namespace std;

struct Matrix {
    int matrix[STATUS_COUNT][STATUS_COUNT];
    Matrix() {
        memset(matrix, 0, sizeof(matrix));
    }
};

class Solution {
public:
    Matrix unit_matrix;
    int dp_init[STATUS_COUNT];
    int K, N;
    const static int MOD = 12357;
    void print_matrix(Matrix &m) {
        int n = 1 << K;
        cout << "-----------" << endl;
        for (int i = 0; i < n; i++) {
            for (int j = 0; j < n; j++) printf("%d ", m.matrix[i][j]);
            printf("\n");
        }
    }
    void solve() {
        cin >> K >> N;  
        if (K > N) swap(K, N);
        compute_matrix();
        //print_matrix(unit_matrix);
        compute_dp_init(); 
        Matrix *m = matrix_pow(unit_matrix, N - 1);
        int result = 0;
        int status_count = (1 << K);
        for (int i = 0; i < (status_count); i++) {
            result += dp_init[i] * m->matrix[i][(status_count)-1];
            result %= MOD;
        }
        printf("%d\n", result);
    }

    void compute_dp_init() {
        int status_count = 1 << K;
        for (int i = 0; i < status_count; i++) {
            dp_init[i] = test_first_line(i);
        }
    }

    void swap(int &i, int &j) {
        int tmp = i;
        i = j;
        j = tmp;
    }

    void compute_matrix() {
        int status_count = 1 << K;
        for (int x = 0; x < status_count; x++) {
            for (int y = 0; y < status_count; y++) {
                if (test_compatible(x, y)) unit_matrix.matrix[x][y] = 1;
            }
        }
    }
    bool test_compatible(int x, int y) {
        for (int i = 0; i < K;) {
            if (x & (1 << i)) {
                if (!(y & (1 << i))) i++;
                else if (i < K - 1 && (y & (1 << i))  && (x & (1 << (i + 1)))  && (y&(1 << (i + 1)))  ) i += 2;
                else return false;
            }
            else {
                if (y & (1 << i)) i++;
                else return false;
            }
        }
        return true;
    }

    Matrix *matrix_multi(Matrix &m1, Matrix &m2) {
        Matrix *result = new Matrix();
        int status_count = 1 << K;
        for (int i = 0; i < status_count; i++) {
            for (int j = 0; j < status_count; j++) {
                result->matrix[i][j] = 0;
                for (int k = 0; k < status_count; k++) {
                    result->matrix[i][j] += m1.matrix[i][k] * m2.matrix[k][j];
                    result->matrix[i][j] %= MOD;
                }
            }
        }
        return result;
    }

    Matrix *matrix_pow(Matrix &m, int p) {
        if (p == 1) return &m;
        Matrix *half = matrix_pow(m, p / 2);
        Matrix *result = matrix_multi(*half, *half);
        if (p % 2 == 0) return result;
        return matrix_multi(*result, m);
    }

    bool test_first_line(int x) {
        for (int i = 0; i < K;) {
            if (!(x & (1 << i))) i++;
            else if (i < K - 1 && (x & (1 << (i + 1))) ) i += 2;
            else return false;
        }
        return true;
    }
};

int main() {
    /*
    FILE *in, *out;
    freopen_s(&in, "input.txt", "r", stdin);
    freopen_s(&out, "output.txt", "w", stdout);
    */
    Solution solution;
    solution.solve();
    return 0;
}
發佈了118 篇原創文章 · 獲贊 17 · 訪問量 29萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章