矩阵幂求解骨牌覆盖数(SOJ 3021)

Posted clearmoonlight

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了矩阵幂求解骨牌覆盖数(SOJ 3021)相关的知识,希望对你有一定的参考价值。

SOJ 3021: Quad Tiling

题意:给出$4 imes N$的矩形以及尺寸为$2 imes 1$的骨牌,求解该矩形能被骨牌覆盖的种数。

分析:起初我自己一直尝试推导出一个递推式,但是一直没有成功。后来看了网上别人给的递推式:$f(n)=f(n-1)+5*f(n-2)+f(n-3)-f(n-4)$,有了这个式子,这个题很好求解了。下面我介绍一种其他的方法。将矩形看作$N imes 4$, 铺骨牌到第$i$行有$6$种情况:$XXXX$, $XOOX$, $OXXO$, $XXOO$, $OOXX$, $OOOO$, 其中$X$表示有骨牌,$O$表示没有骨牌。定义$f(i,1)$, $f(i,2)$, $f(i,3)$, $f(i,4)$, $f(i,5)$, $f(i,6)$分别为上述6种情形的种类数,则我们可以得到以下递推关系:

$f(i+1,1)=f(i,1)+f(i,3)+f(i,4)+f(i,5)+f(i,6)$

$f(i+1,2)=f(i,3)$

$f(i+1,3)=f(i,1)+f(i,2)$

$f(i+1,4)=f(i,1)+f(i,5)$

$f(i+1,5)=f(i,1)+f(i,4)$

$f(i+1,6)=f(i,1)$

矩阵形式为:

$left[egin{array}{c}f(i+1, 1) f(i+1, 2) f(i+1, 3) f(i+1, 4) f(i+1, 5) f(i+1, 6)end{array} ight]=left[egin{array}{cccccc}1 &0 &1 &1 &1 &1 0 &0 &1 &0 &0 &0 1 &1 &0 &0 &0 &0 1 &0 &0 &0 &1 &0 1 &0 &0 &1 &0 &0 1 &0 &0 &0 &0 &0 end{array} ight]left[egin{array}{c}f(i, 1) f(i, 2) f(i, 3) f(i, 4) f(i, 5) f(i, 6)end{array} ight]$. 下面的问题即转化成了矩阵的快速幂算法。

代码:

技术图片
 1 #include<iostream>
 2 #include<string.h>
 3 using namespace std;
 4 int N, M;
 5 struct matrix
 6 {
 7     int P[7][7];
 8     matrix()
 9     {
10         memset(P, 0, sizeof(P));
11     }
12 };
13 matrix matMul(matrix A, matrix B)
14 {
15     matrix C;
16     int i, j, k;
17     for (i = 1; i <= 6; i++)
18         for (j = 1; j <= 6; j++)
19             for (k = 1; k <= 6; k++)
20                 C.P[i][j] = (C.P[i][j] + A.P[i][k] * B.P[k][j]) % M;
21     return C;
22 }
23 matrix matPow(matrix M)
24 {
25     matrix Res;
26     int i;
27     for (i = 1; i <= 6; i++)
28         Res.P[i][i] = 1;
29     int k = N - 1;
30     while (k)
31     {
32         if (k & 1)
33             Res = matMul(Res, M);
34         k >>= 1;
35         M = matMul(M, M);
36     }
37     return Res;
38 }
39 int main()
40 {
41     matrix Con,Ans;
42     Con.P[1][1] = Con.P[1][3] = Con.P[1][4] = Con.P[1][5] = Con.P[1][6] = 1;
43     Con.P[2][3] = 1;
44     Con.P[3][1] = Con.P[3][2] = 1;
45     Con.P[4][1] = Con.P[4][5] = 1;
46     Con.P[5][1] = Con.P[5][4] = 1;
47     Con.P[6][1] = 1;
48     while (scanf("%d%d", &N, &M) == 2 && N > 0)
49     {
50         Ans = matPow(Con);
51         printf("%d
", (Ans.P[1][1] + Ans.P[1][3] + Ans.P[1][4] + Ans.P[1][5] + Ans.P[1][6])%M);
52     }
53     return 0;
54 }
View Code

以上是关于矩阵幂求解骨牌覆盖数(SOJ 3021)的主要内容,如果未能解决你的问题,请参考以下文章

骨牌覆盖小结

[HIHO1143]骨牌覆盖问题·一(矩阵快速幂,递推)

骨牌覆盖 快速幂

hihocoder #1162 矩阵加速dp

快速幂求解

51Nod 1031 骨牌覆盖 | Fibonacci