这里说的主元是主对角线的上的元素。
求解线性方程组
高斯消元法
对于矩阵:
[
.
.
.
.
.
.
.
.
.
]
\begin{bmatrix} .&.&.\\ .&.&.\\ .&.&. \end{bmatrix}
.........
做初等行变换:
- 一行同乘一个实数
- 用一行加减另一行
- 交换两行
因而有了高斯消元法,可以把一个方阵消为上三角矩阵。或者把一个矩阵的靠左的元素构成的方阵消为上三角矩阵。
对于方程组:
I
i
=
1
n
{
∑
j
=
1
n
a
i
,
j
x
j
=
b
i
\overset{n}{{\underset{i=1}{\mathbb{I}}}}\left\{\begin{matrix} {\overset{n}{\underset{j=1}\sum}} a_{i,j}x_j=b_i \end{matrix}\right.
i=1In{j=1∑nai,jxj=bi
可以写成三个矩阵的乘积:
系数矩阵: I i = 1 n ↓ [ I j = 1 n a i , j → ] \overset{n}{{\underset{i=1}{\mathbb{I}}}}\downarrow{\begin{bmatrix} \overset{n}{{\underset{j=1}{\mathbb{I}}}}\underrightarrow{a_{i,j}} \end{bmatrix}} i=1In↓[j=1Inai,j]
未知量矩阵: I i = 1 n ↓ [ x i ] \overset{n}{{\underset{i=1}{\mathbb{I}}}}\downarrow{\begin{bmatrix} x_i\end{bmatrix}} i=1In↓[xi]
常数矩阵: I i = 1 n ↓ [ b i ] \overset{n}{{\underset{i=1}{\mathbb{I}}}}\downarrow{\begin{bmatrix} b_i\end{bmatrix}} i=1In↓[bi]
就有了:
( I i = 1 n ↓ [ I j = 1 n a i , j → ] ) × ( I i = 1 n ↓ [ x i ] ) = I i = 1 n ↓ [ b i ] {\left(\overset{n}{{\underset{i=1}{\mathbb{I}}}}\downarrow{\begin{bmatrix} \overset{n}{{\underset{j=1}{\mathbb{I}}}}\underrightarrow{a_{i,j}} \end{bmatrix}}\right)}\times {\left(\overset{n}{{\underset{i=1}{\mathbb{I}}}}\downarrow{\begin{bmatrix} x_i\end{bmatrix}}\right)}=\overset{n}{{\underset{i=1}{\mathbb{I}}}}\downarrow{\begin{bmatrix} b_i\end{bmatrix}} (i=1In↓[j=1Inai,j])×(i=1In↓[xi])=i=1In↓[bi]
我们把系数矩阵和常数矩阵拼接起来,就得到了增广矩阵:
I
i
=
1
n
↓
[
(
I
j
=
1
n
a
i
,
j
→
)
b
i
]
\overset{n}{{\underset{i=1}{\mathbb{I}}}}\downarrow{\begin{bmatrix} \left( \overset{n}{{\underset{j=1}{\mathbb{I}}}}\underrightarrow{a_{i,j}}\right)&b_i \end{bmatrix}}
i=1In↓[(j=1Inai,j)bi]
对增广矩阵做初等行变换,等价于对原线性方程组进行操作。
高斯消元法的主要过程是:
- 顺序枚举主元,找到主元下面第一个不为0的元素(同一列内,包括主元)。
找不到不为0的元素就继续下一列。 - 把这一行与主元所在的行交换。
- 整一行除以主元,把主元变成1。
- 用主元翻倍去减它下面的数,把下面的数变成0
最终得到一个左侧是上三角矩阵的增广矩阵,此时可以自底而上回带求解。
回带的过程中,我们先有 a n , n ⋅ x n = b n a_{n,n}\cdot x_n=b_n an,n⋅xn=bn,得到 x n x_n xn,再把 x n x_n xn带入 a n − 1 , n − 1 ⋅ x n − 1 + a n − 1 , n ⋅ x n = b n − 1 a_{n-1,n-1}\cdot x_{n-1}+a_{n-1,n}\cdot x_n=b_{n-1} an−1,n−1⋅xn−1+an−1,n⋅xn=bn−1得到 x n − 1 x_{n-1} xn−1。依此类推…
若回代过程中,
a
i
,
i
=
0
a_{i,i}=0
ai,i=0,把方程整理成
a
i
,
i
⋅
x
i
=
b
a_{i,i}\cdot x_i=b
ai,i⋅xi=b的形式,若
b
=
0
b=0
b=0,则相当于
0
⋅
x
=
0
0\cdot x=0
0⋅x=0,有无穷多解。
若
b
≠
0
b\neq0
b=0,就类似于
0
⋅
x
=
3
0\cdot x=3
0⋅x=3的情况,无解。
时间复杂度O( n 3 n^3 n3)
高斯约旦消元法
高斯约旦消元法的过程与高斯消元法类似:
- 顺序枚举主元,找到主元下面第一个不为0的元素(同一列内,包括主元)。
找不到不为0的元素即为无解。 - 把这一行与主元所在的行交换。
- 整一行除以主元,把主元变成1。
- 用主元翻倍去减同一列除了它本身的所有数,把同一列的所有数变成0。(除了主元)
高斯约旦消元法无法判断是无解还是无穷多解,如果有解,得到的增广矩阵的最后一列就是方程组的解。
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int n;
double a[105][105];
bool solve() {
for(int i=1;i<=n;i++) {
int f=i;
while(f<=n&&fabs(a[f][i])<1e-5) f++;
if(f==n+1) return false;
swap(a[i],a[f]);
for(int j=n+1;j>=i;j--) a[i][j]/=a[i][i];
for(int j=1,k=i;j<=n;j++,k=i)
if(i^j)
for(double t=a[j][i];k<=n+1;k++)
a[j][k]-=a[i][k]*t;
}
return true;
}
int main() {
cin>>n;
for(int i=1;i<=n;i++)
for(int j=1;j<=n+1;j++)
cin>>a[i][j];
if(solve())
for(int i=1;i<=n;i++)
printf("%.2lf\n",a[i][n+1]);
else
cout<<"No Solution"<<endl;
}
时间复杂度O( n 3 n^3 n3)
矩阵求逆
定义 I I I为单位矩阵。对于方阵 A A A,若有 A × A − 1 = A − 1 × A = I A\times A^{-1}=A^{-1}\times A=I A×A−1=A−1×A=I,则称 A − 1 A^{-1} A−1是 A A A的逆矩阵。若不存在 A − 1 A^{-1} A−1,则称方阵 A A A不可逆。
矩阵求逆,用高斯约旦消元法:
对于
A
×
A
−
1
=
I
A\times A^{-1}=I
A×A−1=I,把
A
A
A和
I
I
I拼接起来,得到
(
A
,
I
)
(A,I)
(A,I),对
(
A
,
I
)
(A,I)
(A,I)做高斯约旦消元法,变为
(
I
,
A
−
1
)
(I,A^{-1})
(I,A−1),此时右边就是矩阵的逆。如果左侧出现全零列/行,说明矩阵不可逆。
证明较繁,我也不会:
根据理论,首先有矩阵 E E E使得 A × E = A ′ A\times E=A' A×E=A′, E E E等价于做若干次初等行变换。
显然初等行变换可逆。
因此有 I × E = A I\times E=A I×E=A,表示对单位矩阵做若干次初等行变换可以得到 A A A。如果得不到,说明不可逆。
由于 E E E也是一个矩阵,可以把变化矩阵 E E E分解成若干个一次初等行变换矩阵乘积的形式: E = E 1 × E 2 × . . . × E n E=E_1\times E_2\times ...\times E_n E=E1×E2×...×En
因而有:
I
×
E
1
×
E
2
×
.
.
.
×
E
n
=
A
I\times E_1\times E_2\times ...\times E_n=A
I×E1×E2×...×En=A
I
=
A
×
E
1
−
1
×
E
2
−
1
×
.
.
.
×
E
n
−
1
I=A\times E_1^{-1}\times E_2^{-1}\times ...\times E_n^{-1}
I=A×E1−1×E2−1×...×En−1
A
−
1
=
I
×
E
1
−
1
×
E
2
−
1
×
.
.
.
×
E
n
−
1
A^{-1}=I\times E_1^{-1}\times E_2^{-1}\times ...\times E_n^{-1}
A−1=I×E1−1×E2−1×...×En−1
也就是说,只要对 A A A做初等行变换能够变回单位矩阵,则对单位矩阵再做这些初等行变换,就能得到逆矩阵。
对单位矩阵再作这些初等行变换,等价于把 A A A和 I I I拼接起来,一起变换。
QED.(底气不足的证明)
减少高斯消元和高斯约旦消元法误差的一种方法是,在一列中选取绝对值最大的数作为主元,防止大数除以小数,末尾被吃掉。
后记
于是皆大欢喜。