1. 前言
本篇文章是作者学习矩阵时候的一些个人笔记。
由于作者是个高中 OIer,因此并不会涉及到有关线性代数的很多知识,只记录与 OI 有关的矩阵。
这边建议学线性代数的人看一下这篇博文,讲的非常好:理解矩阵(一)(Author:孟岩)。
2. 定义
2.1 向量
讲矩阵之前我们先来讲讲向量。
前置知识:高中数学向量。
向量的英文名是 vector。
由平面向量基本定理可知,任何一个向量都可以被表示成 a e 1 ⃗ + b e 2 ⃗ a\vec{e_1}+b\vec{e_2} ae1+be2,称这个向量的坐标是 ( a , b ) (a,b) (a,b)。这是二维空间内的向量。
现在我们扩展一下,扩展到 n n n 维向量,同样可以将任意一个向量表示成这样: z ⃗ = a 1 e 1 ⃗ + a 2 e 2 ⃗ + . . . + a n e n ⃗ \vec{z}=a_1\vec{e_1}+a_2\vec{e_2}+...+a_n\vec{e_n} z=a1e1+a2e2+...+anen。
那么记 z ⃗ \vec{z} z 的坐标是 ( a 1 , a 2 , . . . , a n ) (a_1,a_2,...,a_n) (a1,a2,...,an)。
这就是向量。有没有发现跟一维数组长得很像?
2.2 矩阵
矩阵说白了就是一堆数框起来,就像下面这样:
[ 2 3 4 1 8 3 5 4 3 ] \begin{bmatrix}2&3&4\\1&8&3\\5&4&3\end{bmatrix} ⎣⎡215384433⎦⎤
也就是个二维数组,其大小为 3 × 3 3 \times 3 3×3。
当然只是这样理解,会导致在做某些毒瘤题的时候搞不清楚到底要干什么,所以还是要把向量拉进来。
理解 1:
从向量的角度看,一个大小为 n × m n \times m n×m 的矩阵实际上就是 n n n 个 m m m 维向量的组合。
比如还是上面这个矩阵,就是 ( 2 , 3 , 4 ) , ( 1 , 8 , 3 ) , ( 5 , 4 , 3 ) (2,3,4),(1,8,3),(5,4,3) (2,3,4),(1,8,3),(5,4,3) 这三个向量的组合。
理解 2:
从坐标系的角度看,我们可以认为矩阵描述了一个坐标系。
这个坐标系是 m m m 维的,该坐标系中的每一个单位向量是一个 n n n 维向量。
显然对于 n = m n=m n=m 的时候上面这句话是成立的,但是对于 n ≠ m n \neq m n=m 的情况上面这句话同样成立。
为什么?
毕竟向量平移之后是一样的,你完全可以将这 m m m 个 n n n 维向量的起点重合,这样这些向量就可以决定这个 m m m 维空间。
如果不理解,看孟岩的理解矩阵(一)。
当然作为一个 OIer,简单记住矩阵的方式就是矩阵是个二维数组,但是坐标系这个理解方式很有必要,否则你会对矩阵乘法蒙圈的。
矩阵里面有一类特殊的矩阵:单位矩阵 I I I,也就是主对角线上元素为 1,其余为 0 的矩阵,像这样:
[ 1 0 0 0 1 0 0 0 1 ] \begin{bmatrix}1&0&0\\0&1&0\\0&0&1\end{bmatrix} ⎣⎡100010001⎦⎤
3. 运算
3.1 矩阵加/减法
矩阵的加法与减法就是对应元素一一相加/减。
能够相加/减的矩阵大小必须相同,都是 n × m n \times m n×m。
比如说下面的矩阵相加减就是个很好的例子:
[ 2 4 8 1 3 2 ] + [ 3 2 9 1 4 6 ] = [ 5 6 17 2 7 8 ] \begin{bmatrix}2&4&8\\1&3&2\end{bmatrix}+\begin{bmatrix}3&2&9\\1&4&6\end{bmatrix}=\begin{bmatrix}5&6&17\\2&7&8\end{bmatrix} [214382]+[312496]=[5267178]
[ 2 4 8 1 3 2 ] − [ 3 2 9 1 4 6 ] = [ − 1 2 − 1 0 − 1 − 4 ] \begin{bmatrix}2&4&8\\1&3&2\end{bmatrix}-\begin{bmatrix}3&2&9\\1&4&6\end{bmatrix}=\begin{bmatrix}-1&2&-1\\0&-1&-4\end{bmatrix} [214382]−[312496]=[−102−1−1−4]
另外还有一种比较少见的矩阵加法方式是直和,参见百度百科。
矩阵加法是满足交换律与结合律的。
3.2 矩阵乘法
先给一下定义:设两个矩阵 A , B A,B A,B,大小分别为 a × b , b × c a \times b,b \times c a×b,b×c,那么 A A A 乘以 B B B 的结果是 C = A B C=AB C=AB,其大小为 a × c a \times c a×c, C C C 中每个元素计算方式如下:
C i , j = ∑ i = 1 a ∑ j = 1 c ∑ k = 1 b A i , k × b k , j C_{i,j}=\sum_{i=1}^{a}\sum_{j=1}^{c}\sum_{k=1}^{b}A_{i,k} \times b_{k,j} Ci,j=i=1∑aj=1∑ck=1∑bAi,k×bk,j
这说明两个矩阵相乘,必须要满足前一个的列数等于后一个的行数。
对于 OIer 而言,更常用的是两个 n × n n \times n n×n 的矩阵相乘。
但是矩阵乘法为什么要这样定义呢?这样定义的意义在哪里?
实际上前面说过矩阵是个坐标系。
因此我们可以认为矩阵乘法 A B AB AB 是表示组成 B B B 的向量们在坐标系 A A A 下面的一个描述,在 A A A 的描述下这些向量所组成的矩阵为 C C C。
矩阵乘法满足结合律,但是并不满足交换律。
对于单位矩阵而言,有一个特殊的性质: I A = I IA=I IA=I。
这边给一下矩阵乘法的代码:
struct Matrix
{
int a[MAXN][MAXN], r, c;
Matrix operator *(const Matrix &fir)
{
Matrix tmp; memset(tmp.a, 0, sizeof(tmp.a));
tmp.r = r; tmp.c = fir.c;
for (int i = 1; i <= r; ++i)
for (int k = 1; k <= c; ++k)
{
int t = a[i][k];
for (int j = 1; j <= fir.c; ++j)
{ tmp.a[i][j] += t * fir.a[k][j]; tmp.a[i][j] %= m; }
}
return tmp;
}
};
注意上述代码的循环顺序与矩阵乘法定义的循环顺序有所不同,实际上这两者是等价的,而上述代码利用了 Cache 的性质卡常,使得矩阵乘法的常数不至于太大。
4. 总结
- 向量:记 z ⃗ = a 1 e 1 ⃗ + a 2 e 2 ⃗ + . . . + a n e n ⃗ \vec{z}=a_1\vec{e_1}+a_2\vec{e_2}+...+a_n\vec{e_n} z=a1e1+a2e2+...+anen 的坐标是 ( a 1 , a 2 , . . . , a n ) (a_1,a_2,...,a_n) (a1,a2,...,an),形如一维数组。
- 矩阵:形如二维数组,可以看作是一些向量的组合,也可以看作是一个坐标系。
- 矩阵加/减法:对应元素相加/减。
- 矩阵乘法:设两个矩阵
A
,
B
A,B
A,B,大小分别为
a
×
b
,
b
×
c
a \times b,b \times c
a×b,b×c,那么
A
A
A 乘以
B
B
B 的结果是
C
=
A
B
C=AB
C=AB,其大小为
a
×
c
a \times c
a×c,
C
C
C 中每个元素计算方式如下:
C i , j = ∑ i = 1 a ∑ j = 1 c ∑ k = 1 b A i , k × b k , j C_{i,j}=\sum_{i=1}^{a}\sum_{j=1}^{c}\sum_{k=1}^{b}A_{i,k} \times b_{k,j} Ci,j=i=1∑aj=1∑ck=1∑bAi,k×bk,j