基础线性代数小记
矩阵乘法
定义
matrix operator*(const matrix& T) {
matrix res = {0};
for(int i=0;i<N;++i)
for(int j=0;j<N;++j)
for(int k=0;k<N;++k)
res.a[i][j] = (res.a[i][j]+a[i][k]*T.a[k][j]%mod) % mod;
return res;
}
常数优化
// 改变循环次序、减少随机访问次数
matrix operator*(const matrix& T) {
matrix res = {0};
int r;
for(int i=0;i<N;++i)
for(int k=0;k<N;++k) {
r = a[i][k];
for(int j=0;j<N;++j)
res.a[i][j] = (res.a[i][j]+r*T.a[k][j]%mod) % mod;
}
}
表示线性变换
THUSCH2017 大魔法师
石头游戏
高斯消元
线性方程组
\[\left[
\begin{array}{cccc}
a_{1,1}&\cdots& a_{1,n} \\
\vdots & \ddots & \vdots \\
a_{n,1} & \cdots & a_{n,n}
\end{array}
\right]
*
\left[
\begin{array}{cccc}
x_1\\
\vdots \\
x_n\\
\end{array}
\right]
=
\left[
\begin{array}{cccc}
C_1 \\
\vdots \\
C_n
\end{array}
\right]
\]
这就是一个线性方程组, 其中, \(x_i\) 是未知数, \(a_{i,j}\) 和 \(C_i\) 都是常数。
显然可以求矩阵逆
矩阵的初等行变换
交换矩阵的任意两行、将某一行所有数乘上一个非零的数、把某一行所有数加上(或减去)另一行对应列的数。
线性方程组的增广矩阵
\[\left[
\begin{array}{cccc}
a_{1,1}&\cdots& a_{1,n} & C_1 \\
\vdots & \ddots & \vdots & \vdots \\
a_{n,1} & \cdots & a_{n,n} & C_n
\end{array}
\right]
\]
高斯消元
对线性方程组的增广矩阵进行初等行变换, 得到的矩阵是另一个线性方程组的增广矩阵, 且这个线性方程组的解与做变换之前的矩阵对应的的线性方程组的解相同(这里不证)。 高斯消元就是通过初等行变换求解线性方程组的。
无唯一解
无解
在消元的过程中, 遇到 \([0,0,\cdots,0] = C_i\) (\(C_i\) 非零)这样的一行,表明某些方程存在矛盾,就无解。
无穷解
主元 : 主元 \(x_i\) 满足, 在消元后的增广矩阵中, 有且仅有一个在第 \(i\) 列的位置 \((r,i)\) 非零且第 \(r\) 行的 \(1\) ~ \(i-1\) 列都为 0, 不是主元的 \(x_i\) 被称为自由元。
如果主元有 n 个, 则方程组有解, 其它情况下, 方程组有无穷多个解。
消元后的增广矩阵的系数不全为零的行的个数就是主元的个数。
例如这个高斯消元后的增广矩阵:
\[\left[
\begin{array}{cccc}
1 &2 &0 &4 \\
0 & 0& 1& 1\\
0& 0& 0& 0
\end{array}
\right]
\]
它意味着
\[\begin{cases}
x_1 = 4 - 2x_2 \\
x_3 = 1
\end{cases}
\]
主元是 \(x_1\) 、 \(x_3\) , 自由元是 \(x_2\)。
void gauss(int N) {
for(int i=1;i<=N;++i) {
int mx=i; for(int j=i+1;j<=N;++j) if(fabs(a[j][i])>fabs(a[mx][i]))mx=j;
for(int j=i;j<=N+1;++j) swap(a[i][j], a[mx][j]);
for(int j=i+1;j<=N;++j)
for(int k=N+1;k>=i;--k)
a[j][k] -= a[i][k] * a[j][i] / a[i][i];
}
for(int i=N;i;--i) {
a[i][N+1] /= a[i][i];
for(int j=i-1;j;--j) a[j][N+1] -= a[i][N+1] * a[j][i];
}
}