矩阵(矩阵快速幂)
矩阵在计算机数学中有比较重要的内容,它可以优化很多推论,在这里我们将简单介绍一下。
矩阵是什么
由
n
×
m
n\times m
n×m个数
a
i
j
(
i
=
1
,
2
,
…
,
n
,
j
=
1
,
2
,
…
,
m
)
a_{ij}(i=1,2,\dots,n,j=1,2,\dots,m)
aij(i=1,2,…,n,j=1,2,…,m)排成的
m
m
m行
n
n
n列的数表(是一组数)。通用形式:
[
a
1
a
2
⋯
⋯
a
n
b
1
b
2
⋯
⋯
b
n
⋯
⋯
⋯
⋯
⋯
z
1
z
2
⋯
⋯
z
n
]
\left[ \begin{matrix} a_1 & a_2 & \cdots\cdots & a_n\\ b_1 & b_2 & \cdots\cdots & b_n\\ \cdots & \cdots & \cdots\cdots & \cdots\\ z_1 & z_2 & \cdots\cdots & z_n \end{matrix} \right]
a1b1⋯z1a2b2⋯z2⋯⋯⋯⋯⋯⋯⋯⋯anbn⋯zn
下面了解一些特殊的矩阵:
- 行(列)矩阵:只有一行(列)的矩阵,又称之为行(列)向量。
- 同型矩阵:行数和列数都相等的两个矩阵。
- 零矩阵:所有元素为 0 0 0的矩阵,记为 O O O,不同型的零矩阵是不相等的。
- 对角矩阵:对角线元素为 a 1 , a 2 , … , a n a_1,a_2,\dots,a_n a1,a2,…,an,其余元素均为 0 0 0的方阵。
- 单位矩阵:对角线元素为 1 1 1,其余元素为 0 0 0的方阵。
加法运算
两个矩阵进行一般的加法运算的前提是这两个矩阵为同型矩阵,我们只需要将对应位置的元素相加即可。
A
=
[
a
1
a
2
a
3
b
1
b
2
b
3
c
1
c
2
c
3
]
,
B
=
[
d
1
d
2
d
3
e
1
e
2
e
3
f
1
f
2
f
3
]
,
A
+
B
=
[
a
1
+
d
1
a
2
+
d
2
a
3
+
d
3
b
1
+
e
1
b
2
+
e
2
b
3
+
e
3
c
1
+
f
1
c
2
+
f
2
c
3
+
f
3
]
A=\left[ \begin{matrix} a_1 & a_2 & a_3\\ b_1 & b_2 & b_3\\ c_1 & c_2 & c_3 \end{matrix} \right] ,B=\left[ \begin{matrix} d_1 & d_2 & d_3\\ e_1 & e_2 & e_3\\ f_1 & f_2 & f_3 \end{matrix} \right] ,A+B=\left[ \begin{matrix} a_1+d_1 & a_2+d_2 & a_3+d_3\\ b_1+e_1 & b_2+e_2 & b_3+e_3\\ c_1+f_1 & c_2+f_2 & c_3+f_3 \end{matrix} \right]
A=
a1b1c1a2b2c2a3b3c3
,B=
d1e1f1d2e2f2d3e3f3
,A+B=
a1+d1b1+e1c1+f1a2+d2b2+e2c2+f2a3+d3b3+e3c3+f3
在矩阵的加法运算中,满足交换律和结合律,也就是
A
+
B
=
B
+
A
,
(
A
+
B
)
+
C
=
A
+
(
B
+
C
)
A+B=B+A,(A+B)+C=A+(B+C)
A+B=B+A,(A+B)+C=A+(B+C)。
减法运算
在实数运算中,减法为加法的逆运算,同样的,在矩阵运算中也是如此。
A
=
[
a
1
a
2
a
3
b
1
b
2
b
3
c
1
c
2
c
3
]
,
B
=
[
d
1
d
2
d
3
e
1
e
2
e
3
f
1
f
2
f
3
]
,
A
−
B
=
[
a
1
−
d
1
a
2
−
d
2
a
3
−
d
3
b
1
−
e
1
b
2
−
e
2
b
3
−
e
3
c
1
−
f
1
c
2
−
f
2
c
3
−
f
3
]
A=\left[ \begin{matrix} a_1 & a_2 & a_3\\ b_1 & b_2 & b_3\\ c_1 & c_2 & c_3 \end{matrix} \right] ,B=\left[ \begin{matrix} d_1 & d_2 & d_3\\ e_1 & e_2 & e_3\\ f_1 & f_2 & f_3 \end{matrix} \right] ,A-B=\left[ \begin{matrix} a_1-d_1 & a_2-d_2 & a_3-d_3\\ b_1-e_1 & b_2-e_2 & b_3-e_3\\ c_1-f_1 & c_2-f_2 & c_3-f_3 \end{matrix} \right]
A=
a1b1c1a2b2c2a3b3c3
,B=
d1e1f1d2e2f2d3e3f3
,A−B=
a1−d1b1−e1c1−f1a2−d2b2−e2c2−f2a3−d3b3−e3c3−f3
数乘
在数乘运算中,我们类比向量来进行理解,在数乘向量运算中,只需要将向量中的每个元素乘上那个数就可以了,数乘矩阵也是如此。
A
=
[
a
1
a
2
a
3
b
1
b
2
b
3
c
1
c
2
c
3
]
,
3
×
A
=
[
3
×
a
1
3
×
a
2
3
×
a
3
3
×
b
1
3
×
b
2
3
×
b
3
3
×
c
1
3
×
c
2
3
×
c
3
]
A=\left[ \begin{matrix} a_1 & a_2 & a_3\\ b_1 & b_2 & b_3\\ c_1 & c_2 & c_3 \end{matrix} \right] ,3\times A=\left[ \begin{matrix} 3\times a_1 & 3\times a_2 & 3\times a_3\\ 3\times b_1 & 3\times b_2 & 3\times b_3\\ 3\times c_1 & 3\times c_2 & 3\times c_3 \end{matrix} \right]
A=
a1b1c1a2b2c2a3b3c3
,3×A=
3×a13×b13×c13×a23×b23×c23×a33×b33×c3
数乘矩阵运算中,满足如下运算律:
(
λ
×
μ
)
×
A
=
λ
×
(
μ
×
A
)
,
(
λ
+
μ
)
×
A
=
λ
×
A
+
μ
×
A
,
λ
(
A
+
B
)
=
λ
×
A
+
λ
×
B
(\lambda\times\mu)\times A=\lambda\times(\mu\times A),(\lambda+\mu)\times A=\lambda\times A+\mu\times A,\lambda(A+B)=\lambda\times A+\lambda\times B
(λ×μ)×A=λ×(μ×A),(λ+μ)×A=λ×A+μ×A,λ(A+B)=λ×A+λ×B。
乘法运算
再次先说明:矩阵相乘前一个矩阵的列数必须等于后一个矩阵的行数 A m × s × B s × n A_{m\times s}\times B_{s\times n} Am×s×Bs×n,乘积矩阵的函数为前一个矩阵的行数,列数为后一个矩阵的列数 C m × n C_{m\times n} Cm×n。
现在我们设 C = A × B C=A\times B C=A×B(三个都是矩阵),那么就有 C [ i ] [ j ] = ∑ i = 1 s ( A [ i ] [ k ] × B [ k ] [ j ] ) C[i][j]=\sum_{i=1}^s(A[i][k]\times B[k][j]) C[i][j]=∑i=1s(A[i][k]×B[k][j])。通俗的说,结果矩阵的第 i i i行第 j j j列等于矩阵 A A A第 i i i行与矩阵 B B B第 j j j列分别乘积的和(现在明白为什么矩阵乘法要求 A A A的行数与 B B B的列数相同了吧,因为要保证有数相乘,若不相等会导致缺少一些项)
在普通的乘法中,一个数乘 1 1 1还是等于它本身,在矩阵乘法中也有这么一个 “ 1 ” “1” “1”,它就是单位矩阵。不同于普通乘法中的单位 1 1 1,对于不同矩阵他们的单位矩阵大小是不同的对于 n × m n\times m n×m的矩阵,它的单位矩阵大小为 m × m m\times m m×m,对于 m × n m\times n m×n的矩阵,它的单位矩阵大小为 n × n n\times n n×n。也就是说单位矩阵都是正方形的,这是因为只有正方形的矩阵能保证结果和前一个矩阵形状相同,单位矩阵的元素非 0 0 0即 1 1 1,从左上角到右下角的对角线上元素皆为 1 1 1,其他皆为 0 0 0。
矩阵快速幂
了解了这么多,我们现在来看矩阵快速幂,矩阵快速幂就是将矩阵和快速幂相结合,由于矩阵乘法满足结合律,所以我们只需要把它按照一般的快速幂来写即可。
int n, m, p, k;
struct Mat{
int arr[10][10];
};
Mat Add(Mat x, Mat y){
Mat temp;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
temp.arr[i][j] = x.arr[i][j] + y.arr[i][j];
}
}
return temp;
}
Mat Sub(Mat x, Mat y){
Mat temp;
for(int i = 1; i <= n; i++){
for(int j = 1; j <= m; j++){
temp.arr[i][j] = x.arr[i][j] - y.arr[i][j];
}
}
return temp;
}
Mat Mul(Mat x, Mat y){
Mat temp;
memset(temp.arr,0,sizeof(temp.arr));
for (int i = 1; i <= n; i++) {
for (int j = 1; j <= m; j++) {
for (int k = 1; k <= p; k++) {
temp.arr[i][j] = temp.arr[i][j] + x.arr[i][k] * y.arr[k][j];
}
}
}
return temp;
}
int main(){
Mat res, a;
cin >> n >> k;
m = n;
p = n;
for(int i = 1; i <= n; i++){
res.arr[i][i] = 1;
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
cin >> a.arr[i][j];
}
}
while(k){
if(k & 1) res = Mul(res,a);
a = Mul(a,a);
k >>= 1;
}
for(int i = 1; i <= n; i++){
for(int j = 1; j <= n; j++){
cout << res.arr[i][j] << " ";
}
cout << endl;
}
return 0;
}