問題描述
有一個 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;
}