矩阵入门
矩阵
向量与矩阵
在线性代数中,向量分为列向量和行向量。
向量也是特殊的矩阵,行向量可以看作是一个 \(1\times n\) 的矩阵,例如下面这样:
列向量可以看作是一个 \(n\times 1\) 的矩阵,例如下面这样:
也可以写成由行向量转置而来的,比如上面的列向量可以这样写:
线性代数的主要研究对象是列向量,约定使用粗体小写字母表示列向量。在用到大量向量与矩阵的线性在数中,不引起混淆的情况下,在手写时,字母上方的向量记号可以省略不写。
如果想要表示行向量,需要在粗体小写字母右上方写转置符号。行向量在线性代数中一般表示方程。
引入
矩阵的引入来自于线性方程组,与向量类似,都是为了能以更少的字符来表示更多的信息,就比如下面的线性方程组:
一般使用圆括号或方括号来表示矩阵。上面的方程组写成矩阵的形式就是:
我觉得方括号更整齐好看于是就用的方括号
简记为:
表示位置数列向量 \(x\) 左乘一个矩阵 \(A\),得到列向量 \(b\)。这个式子可以认为是线性代数的基本形式。
线性代数主要研究的运算模型是内积,内积是先相乘再相加,是行向量左乘列向量,得到一个数的过程。矩阵乘法是内积的拓展,矩阵乘法等价于左边矩阵拿出来一行与右边矩阵抽出一列来进行内积,得到结果矩阵的对应元素,口诀「左行右列」。
定义
对于矩阵 \(A\),主对角线是指 \(A_{i,i}\) 的元素。
一般用 \(I\) 来表示单位矩阵,就是主对角线上为 \(1\),其余位置为 \(0\) 的矩阵。
同型矩阵
两个矩阵,行数和列数对应相同,则称为同型矩阵。
方阵
行数等于列数的矩阵称为方阵。方阵是一种特殊的矩阵。对于「\(n\) 阶矩阵」的习惯表述,实际上讲的就是 \(n\) 阶方阵。阶数相同的方阵为同型矩阵。
主对角线
方阵中行数等于列数的元素构成主对角线
对称矩阵
如果将方阵的元素关于主对角线对称,即对于任意的 \(i\) 和 \(j\),都有 \(a_{ij}=a_{ji}\),则称该方阵为对称矩阵,其中 \(a_{ij}\) 表示矩阵 \(A\) 中第 \(i\) 行第 \(j\) 列的元素
对角矩阵
主对角线之外的元素均为 \(0\) 的方阵称为对角矩阵,一般记作:
式子中的 \(\lambda_{1},\ldots,\lambda_{n}\) 是主对角线上的元素。
对角矩阵是对称矩阵。
如果对角矩阵的元素均为 \(1\),则称为单位矩阵,记为 \(I\)。只要乘法可以进行,任何矩阵乘单位矩阵仍保持不变。
三角矩阵
如果方阵主对角线左下方的元素均为 \(0\),则称为上三角矩阵,如果方阵主对角线右上方元素均为 \(0\),则称为下三角矩阵。
两个上(下)三角矩阵的乘积仍是上(下)三角矩阵。如果对角线元素均非 \(0\),则上(下)三角矩阵可逆,逆也是上(下)三角矩阵。
单位三角矩阵
如果上三角矩阵 \(A\) 的对角线全为 \(1\),则称 \(A\) 是单位上三角矩阵。如果下三角矩阵 \(A\) 的对角线全为 \(1\),则称 \(A\) 是单位下三角矩阵。
两个单位上(下)三角矩阵的乘积仍然是单位上(下)三角矩阵,单位上(下)三角矩阵的逆也是单位上(下)三角矩阵。
运算
矩阵的线性运算分为加减法与数乘,他们均为逐个元素进行。只有同型矩阵之间可以对应相加减。
矩阵的转置
矩阵的转置,就是在矩阵的右上角写上转置「T」记号,表示将矩阵的行与列互换。
对称矩阵转置前后保持不变。
矩阵乘法
矩阵的乘法是向量内积的推广。
矩阵相乘只有在第一个矩阵的列数和第二个矩阵的行数相同时才有意义。
设 \(A\) 为 \(P\times M\) 的矩阵,\(B\) 为 \(M\times Q\) 的矩阵,设 \(C\) 矩阵为矩阵 \(A\) 与 \(B\) 的乘积。
其中矩阵 \(C\) 中的第 \(i\) 行第 \(j\) 列的元素可以表示为:
找了张好理解的图片:
原文:B2105 矩阵乘法 题解 - Daidly's Blog - 洛谷博客
在矩阵乘法中,结果 \(C\) 矩阵的第 \(i\) 行第 \(j\) 列的数,就是由矩阵 \(A\) 第 \(i\) 行 \(M\) 个数与矩阵 \(B\) 第 \(j\) 列 \(M\) 个数分别相乘再相加得到的。这里的相乘再相加,就是向量的内积。乘积矩阵中第 \(i\) 行第 \(j\) 列的数恰好是乘数矩阵 \(A\) 第 \(i\) 个行向量与乘数矩阵 \(B\) 第 \(j\) 个列向量的内积。
注意矩阵乘法满足结合律但不满足一般的交换律
如果不理解的话可以看看这个:http://matrixmultiplication.xyz/
利用结合律,矩阵乘法可以利用快速幂的思想来优化
小优化
对于较小的矩阵,可以直接手动展开循环来减小常数。
可以重新排列循环以提高空间局部性,这样的优化不会改变时间复杂度,但是可以得到常数上的提升。
矩阵快速幂
快速幂都会,那矩阵快速幂呢?
在后面的矩阵加速递推等都需要用到他,原理是什么?
大致的写法分为两种:重载运算符和函数,我个人比较喜欢函数的写法。
我们可以按正常的快速幂写法来,区别就是在其中的底数换成了矩阵,然后写一个矩阵乘法的函数来进行相乘即可。
参考代码:
#include<bits/stdc++.h>
#define int long long
#define P 1000000007
#define endl '\n'
#define N 110
using namespace std;
struct sb{int m[N][N];}ans;
int n,k;
inline int read(){int x=0,f=1;char ch=getchar();while(!isdigit(ch)){f=ch!='-';ch=getchar();}while(isdigit(ch)){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();}return f?x:-x;}
inline sb cheng(sb a,sb b)
{
sb c;
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
c.m[i][j]=0;
for(int k=1;k<=n;k++)
c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j])%P;
}
}
return c;
}
inline sb jzksm(sb x,int y)
{
sb res=x;y--;
while(y)
{
if(y&1)res=cheng(res,x);
x=cheng(x,x);
y>>=1;
}
return res;
}
signed main()
{
n=read();k=read();
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
ans.m[i][j]=read();
ans=jzksm(ans,k);
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
cout<<ans.m[i][j]<<" ";
cout<<endl;
}
return 0;
}
方阵的逆
方阵 \(A\) 的逆矩阵 \(P\) 是使得 \(A\times P=I\) 的矩阵。
逆矩阵不一定存在,如果存在可以用高斯消元来求解。
方阵的行列式
行列式是方阵的一种运算。
看待线性方程组的两种视角
看待一个矩阵 \(A\),有两种视角。
第一种观点:按行看,观察 \(A\) 的每一行,这样一来把 \(A\) 看作方程组。于是就有了消元法解方程的过程。
第二种观点:按列看,观察 \(A\) 的每一列,\(A\) 本身也是由列向量构成的。此时相当于把变换 \(A\) 本身看成了列向量组,而 \(x\) 是未知数系数,思考 \(A\) 当中的这组列向量能不能配上未知数,凑出列向量 \(b\) 。
例如:文章开头的例子变为:
解方程变为研究是否可以通过调整三个系数 \(x\) 使得给定的三个基向量能够凑出结果的向量。
按列看比按行看更新颖。在按列看的视角下,可以研究线性无关与线性相关。
矩阵乘法的应用
矩阵加速递推
斐波那契数列大家应该非常熟悉,在学习递归或者递推的时候应该是有做过相关题目的,在斐波那契数列里面,\(F_{1}=F_{2}=1,F_{i}=F_{i-1}+F_{i-2}(i\ge3)\)。
我们在之前的题目遇见的求斐波那契数列第 \(n\) 项的值范围都是很小的,因为递归的速度太慢,如果数据范围到达了 \(10^{18}\) 那么我们递推也是一定 TLE 的,所以这个时候就需要用到我们的矩阵加速递推。
设 \(Fib(n)\) 表示一个 \(1\times 2\) 的矩阵 \(\begin{bmatrix}F_{n}&F_{n+1}\end{bmatrix}\) 。我们希望依据 \(Fib(n-1)=\begin{bmatrix}F_{n-1}&F_{n-2}\end{bmatrix}\) 推出 \(Fib(n)\)。
试着来推导一个矩阵 \(\text{base}\),使 \(Fib(n-1)\times \text{base}=Fib(n)\),也就是 \(\begin{bmatrix}F_{n-1}&F_{n-2}\end{bmatrix}\times \text{base}=\begin{bmatrix}F_{n}&F_{n-1}\end{bmatrix}\)。
因为 \(F_{n}=F_{n-1}+F_{n-2}\),所以 \(\text{base}\) 矩阵第一列一定是 \(\begin{bmatrix}1\\1\end{bmatrix}\),这样才能在进行乘法运算的时候才能令 \(F_{n-1}\) 与 \(F_{n-2}\) 相加,从而得出 \(F_{n}\)。同理,为了得出 \(F_{n-1}\),矩阵 \(\text{base}\) 的第二列应该为 \(\begin{bmatrix}1\\0\end{bmatrix}\)。
综上所述,\(\text{base}=\begin{bmatrix}1&1\\1&0\end{bmatrix}\) ,原式化为 \(\begin{bmatrix}F_{n-1}&F_{n-2}\end{bmatrix}\times \begin{bmatrix}1&1\\1&0\end{bmatrix}=\begin{bmatrix}F_{n}&F_{n-1}\end{bmatrix}\)。
定义初始矩阵 \(ans=\begin{bmatrix}F_{2}&F_{1}\end{bmatrix}=\begin{bmatrix}1&1\end{bmatrix}\),\(\text{base}=\begin{bmatrix}1&1\\1&0\end{bmatrix}\)。那么,\(F_{n}\) 就等于 \(ans\times \text{base}^{n-2}\) 这个矩阵的第一行第一列的元素,也就是 \(\begin{bmatrix}1&1\end{bmatrix}\times \begin{bmatrix}1&1\\1&0\end{bmatrix}^{n-2}\) 的第一行第一列的元素。
注意矩阵乘法不满足交换律,所以不能将两个矩阵反过来,另外,对于 \(n\le 2\) 的情况,可以直接输出 \(1\)。
参考代码:
#include<bits/stdc++.h>
#define int long long
#define P 1000000007
#define N 110
using namespace std;
int n;
struct sb{int m[N][N];}ans,base;
inline sb cheng(sb a,sb b,int ok)
{
sb c;
for(int i=1;i<=ok;i++)
{
for(int j=1;j<=ok;j++)
{
c.m[i][j]=0;
for(int k=1;k<=ok;k++)
c.m[i][j]=(c.m[i][j]+a.m[i][k]*b.m[k][j])%P;
}
}
return c;
}
inline sb jzksm(sb x,int y)
{
sb res=x;y--;
while(y)
{
if(y&1)res=cheng(res,x,2);
x=cheng(x,x,2);
y>>=1;
}
return res;
}
signed main()
{
cin>>n;
if(n==1||n==2){puts("1");return 0;}
ans.m[1][1]=1;ans.m[1][2]=1;
base.m[1][1]=1;base.m[1][2]=1;
base.m[2][1]=1;base.m[2][2]=0;
base=jzksm(base,n-2);
ans.m[1][1]=(base.m[1][1]+base.m[1][2])%P;
cout<<ans.m[1][1]<<endl;
return 0;
}
初等矩阵
以下三种矩阵称为初等矩阵。
倍乘矩阵
倍乘矩阵是一种特殊的对角矩阵。
表示一个对角矩阵,主对角线上第 \(i\) 个元素为 \(k\),并且规定 \(k\) 不能为 \(0\),其余的元素全部为 \(1\)。
特别的,当 \(k\) 等于 \(1\) 的时候,\(D_{i}(1)\) 就是单位矩阵 \(I\)。
对换矩阵
对换矩阵是一种特殊的对称矩阵。
对换矩阵的元素全是 \(1\) 和 \(0\),主对角线上其余元素均为 \(1\),仅有第 \(i\) 个元素和第 \(j\) 个元素为 \(0\),而在第 \(i\) 行第 \(j\) 列、第 \(j\) 行第 \(i\) 列上的两个元素为 \(1\)。
对换矩阵要求 \(i\ne j\)。
倍加矩阵
倍加矩阵是在单位矩阵 \(I\) 的基础上,令第 \(i\) 行第 \(j\) 列为 \(k\)。
倍加矩阵要求 \(i\ne j\),如果 \(k=0\),则 \(T\) 退化为单位矩阵 \(I\)。
倍加矩阵是一种上三角或下三角矩阵。
初等变换
不仅限于方阵,对于一般的矩阵 \(A\),可以进行初等行变换和初等列变换,统称为初等变换。
初等行变换与初等列变换一样,都有 3 种:倍乘、对换、倍加。这里先介绍初等行变换:
-
第 \(i\) 行乘非零数 \(k\) :\(B\to D_{i}(k)B\)
-
第 \(i,j\) 行互换:\(B\to P_{ij}B\)
-
第 \(j\) 行乘 \(k\) 加到第 \(i\) 行:\(B\to T_{ij}(k)B\)
将上述操作的行改为列,即得到初等列变换。
在初等变换中,对换可以通过倍乘和倍加实现。显然,倍加不能通过倍乘和对换实现。借助行列式的知识,以及下文的初等变换与矩阵乘法的等价性,也能说明倍乘不能通过倍加和对换实现。
因此,相较对换而言,倍乘和倍加是更为本质的操作。对换操作是为了在消元法中,保证消元的有序,而引入的辅助操作。
初等变换与矩阵乘法
可以发现三类初等矩阵都是在单位矩阵 \(I\) 上进行一次相应的变换得到的结果。
无论矩阵 \(A\) 是否为方阵,对矩阵 \(A\) 进行初等行变换,等价于对矩阵 \(A\) 左乘初等矩阵。对矩阵 \(A\) 进行初等列变换,等价于对矩阵 \(A\) 右乘初等矩阵。
倍乘操作
左乘一个倍乘矩阵 \(D_{i}(k)\),等价于将第 \(i\) 行变为 \(k\) 倍。右乘一个倍乘矩阵 \(D_{i}(k)\),等价于将第 \(i\) 列变为 \(k\) 倍。
对角矩阵乘对角矩阵还是对角矩阵,对于对角矩阵的乘法,将主对角线上对应的元素相乘。由于单位矩阵是特殊的倍乘矩阵,而倍乘矩阵要求 \(k\) 不为 \(0\),可以看出,只要对角矩阵主对角线上的元素均非 \(0\),就可以拆分为倍乘矩阵的乘积。
对于一般的对角矩阵,无论元素是否为 \(0\),也有相应的结论。左乘对角矩阵,等价于将对应的行变为原来的若干倍,倍数恰为对角矩阵主对角线上的相应元素。右乘对角矩阵,是对相应的列进行同样操作。
由于倍乘矩阵 \(D_{i}(k)\) 的行列式为 \(k\),对于方阵的行或列进行倍乘操作之后,方阵对应的行列式变为原来的 \(k\) 倍。对角矩阵的行列式为主对角线元素的乘积。
倍乘矩阵的乘法可以交换,对角矩阵的乘法也可以交换,在乘法只有对角矩阵时,顺序可以任意排列。
单位阵对应的倍乘操作为保持矩阵 \(A\) 不变,在实际应用中不进行这样的操作。
对换操作
左乘一个对换矩阵 \(P_{ij}\),等价于将第 \(i\) 行与第 \(j\) 行交换。右乘一个对换矩阵 \(P_{ij}\),等价于将第 \(i\) 列与第 \(j\) 列交换。
置换:可以理解为把一个有序的数列打乱一次。打乱后可以和原序列一样。
与倍乘矩阵和对角矩阵的关系类似,这里引入置换矩阵的概念。置换矩阵是一个方阵,每行每列均恰有一个 \(1\),其余位置均为 \(0\)。单位矩阵 \(I\) 也是特殊的置换矩阵。
置换矩阵和对于单位矩阵 \(I\) 的行进行置换操作一致,也和对于单位矩阵 \(I\) 的列进行置换操作一致。单位矩阵 \(I\) 本身对应于恒等变换。
左乘一个置换矩阵等价于对原矩阵的行进行置换(也就是以行为单位进行置换),右乘一个置换矩阵等价于对原矩阵的列进行置换,相应置换的方法和对于单位矩阵 \(I\) 的行或列进行置换操作一致。
置换矩阵与置换完全对应,置换矩阵构成的乘法群与置换群同构。由于有定理,在恒等变换视为零个对换的乘积的情形下,任何置换都可以拆为对换的乘积,因此任何置换矩阵也可以拆分为对换矩阵的乘积。
由于对换矩阵的行列式为 \(-1\),对于方阵的行或列进行对换操作之后,方阵对应的行列式变为原来的 \(-1\) 倍。
对换矩阵的乘法不可交换,置换矩阵的乘法也不可交换。
置换矩阵的行列式为 \((-1)^{p}\),其中 \(p\) 为置换矩阵对应置换的逆序数,即置换拆分为对换乘积的个数。
倍加操作
左乘倍加矩阵 \(T_{ij}(k)\) 等价于把第 \(j\) 行的 \(k\) 倍加到第 \(i\) 行上。右乘倍加矩阵 \(T_{ij}(k)\) 等价于把第 \(i\) 列的 \(k\) 倍加到第 \(j\) 列上。
如果难以记忆,可以观察倍加阵 \(T_{ij}(k)\) 是对单位矩阵 \(I\) 进行了怎样的操作,两者是对应的,左乘是对行的操作,右乘是对列的操作,符合口诀左行右列。
由于倍加矩阵的行列式为 \(1\),对于方阵进行倍加操作之后,方阵对应的行列式不变。
倍加矩阵的乘法不可交换。
单位矩阵对应的倍加操作为保持矩阵 \(A\) 不变,在实际应用中不进行这样的操作。
上三角矩阵
倍加矩阵是一种上三角矩阵或者下三角矩阵。由于两种矩阵关于主对角线对称,这里讨论上三角矩阵。事实上在这个例子中,只需要进行初等行变换,而不需要列变换。
如果一个上三角矩阵的主对角线均为 \(1\),则可拆分为一连串倍加矩阵的乘积。拆分的顺序为,先对单位矩阵 的第一行进行倍加操作,再对单位矩阵 \(I\) 的第二行进行倍加操作,以此类推,直到每一行均被操作完毕为止。
由于倍加矩阵的乘法不可交换,上述操作不可调换顺序。
如果一个上三角矩阵的主对角线均非 \(0\),则可拆分为一连串倍加矩阵和倍乘矩阵的乘积。可以在操作单位矩阵 \(I\) 的每一行时,先将该行进行倍乘操作,效果为主对角线元素变为指定非零值。
如果一个上三角矩阵的主对角线存在 \(0\),则不可拆分为一连串初等矩阵的乘积。
无论上三角矩阵的主对角线上是否有 \(0\),上三角矩阵的行列式等于主对角线元素乘积,与对角阵一致。
倍加操作将方阵转化为对角阵
只使用倍加操作可以使任意一个方阵变为对角矩阵,这个例子既需要初等行变换也需要初等列变换。
如果方阵的第一行和第一列存在非零元素,则可以通过倍加办法将左上角元素变为非零,进而借助初等行变换和初等列变换,将第一行和第一列除了左上角元素以外,均变为 \(0\)。
如果方阵的第一行和第一列已经均为 \(0\),则直接看第二行和第二列即可。
借助这个办法,甚至可以规定对角阵的非零元素均在左上角。
如果方阵的第一行和第一列已经均为 \(0\),则看剩余的行列是否有非零元素,只要有非零元素,则可以通过倍加操作将第一行和第一列中某个元素变为非 \(0\),进而化归为一开始的情况,使得左上角元素非 \(0\)。
仅当剩余的行列也均没有非零元素时,左上角无法变为非零元素,此时剩余的方阵已经为零矩阵。
标准型矩阵
借助初等变换可以将任意的矩阵,无论形状,化归为标准形矩阵。
标准形矩阵拥有一个单位矩阵 \(I\) 作为子矩阵位于左上角,其余部分均为 \(0\)。化归的办法与将方阵转化为对角阵的操作类似,并需要借助倍乘操作使左上角非零元素变为 \(1\)。
矩阵转化为标准形矩阵后,含有元素 \(1\) 的个数恰好为矩阵的秩。
可逆矩阵
设 \(A\) 是一个 \(n\) 阶矩阵。如果存在一个 \(n\) 阶矩阵 \(B\),使得 \(AB=BA=I\),那么 \(A\) 叫做一个可逆矩阵或非奇异矩阵,\(B\) 叫做 \(A\) 的逆矩阵,并记为 \(A^{-1}\)。
如果矩阵 \(A\) 可逆,那么 \(A\) 的逆矩阵由 \(A\) 唯一确定。
可逆矩阵 \(A\) 的逆 \(A^{-1}\) 也可逆,并且 \(A^{-1}\) 的逆就是 \(A\)。
两个可逆矩阵 \(A\) 和 \(B\) 的乘积 \(AB\) 也可逆,并且逆为 \(B^{-1}A^{-1}\)。
可逆矩阵 \(A\) 的转置 \(A^{T}\) 也可逆,并且转置的逆等于逆的转置。
本文来自博客园,作者:北烛青澜,转载请注明原文链接:https://www.cnblogs.com/Multitree/p/17421265.html
The heart is higher than the sky, and life is thinner than paper.