Skip to content

高斯消元学习笔记

检测到 KaTeX 加载失败,可能会导致文中的数学公式无法正常渲染。

#前置知识

#矩阵

请参阅《矩阵学习笔记》。

#线性方程组的矩阵表示法

线性方程组是由 nnmm 元一次方程共同构成的。例如,有线性方程组如下:

{x1+2x2x3=62x1+x23x3=9x1x2+2x3=7(1)\tag{1} \begin{cases} \begin{aligned} x_1 + 2 x_2 - x_3 &= -6 \\ 2 x_1 + x_2 - 3 x_3 &= -9 \\ - x_1 - x_2 + 2 x_3 &= 7 \\ \end{aligned} \end{cases}

该方程组的所有系数可以写成一个 n×mn \times m 的「系数矩阵」:

[121213112]\begin{bmatrix} 1 & 2 & -1 \\ 2 & 1 & -3 \\ -1 & -1 & 2 \\ \end{bmatrix}

加上等号右侧的常数项可以写成一个 n×(m+1)n \times (m + 1) 的「增广矩阵」:

[121621391127]\left[ \begin{array}{ccc|c} 1 & 2 & -1 & -6 \\ 2 & 1 & -3 & -9 \\ -1 & -1 & 2 & 7 \\ \end{array} \right]

#初等行列变换

矩阵的初等行变换包括以下几种操作:
  1. 将某一行乘一个非零的数;
  2. 交换某两行;
  3. 将某行的若干倍加到另一行。

同理,我们也可以定义矩阵的初等列变换。这两种变换统称矩阵的初等行列变换。

#高斯消元法

高斯消元是一种通过初等行列变换将增广矩阵变为简化阶梯矩阵的线性方程组求解方法。

#引入

使用若干次初等行变换求解上文中提到的方程组 (1)(1),过程如下:

[121621391127][121603131127][121603130111][121601110113][121601110026][121601110013]\begin{aligned} & \left[ \begin{array}{ccc|c} 1 & 2 & -1 & -6 \\ 2 & 1 & -3 & -9 \\ -1 & -1 & 2 & 7 \\ \end{array} \right] \\ \Rarr& \left[ \begin{array}{ccc|c} 1 & 2 & -1 & -6 \\ 0 & -3 & -1 & 3 \\ -1 & -1 & 2 & 7 \\ \end{array} \right] \\ \Rarr& \left[ \begin{array}{ccc|c} 1 & 2 & -1 & -6 \\ 0 & -3 & -1 & 3 \\ 0 & 1 & 1 & 1 \\ \end{array} \right] \\ \Rarr& \left[ \begin{array}{ccc|c} 1 & 2 & -1 & -6 \\ 0 & 1 & 1 & 1 \\ 0 & -1 & -1 & 3 \\ \end{array} \right] \\ \Rarr& \left[ \begin{array}{ccc|c} 1 & 2 & -1 & -6 \\ 0 & 1 & 1 & 1 \\ 0 & 0 & 2 & 6 \\ \end{array} \right] \\ \Rarr& \left[ \begin{array}{ccc|c} 1 & 2 & -1 & -6 \\ 0 & 1 & 1 & 1 \\ 0 & 0 & 1 & 3 \\ \end{array} \right] \\ \end{aligned}

最后得到的矩阵被称为「阶梯形矩阵」,它的系数矩阵部分被称为「上三角矩阵」,这个矩阵表达的信息为:

[121601110013]{x1+2x2x3=6x2+x3=1x3=3\left[ \begin{array}{ccc|c} 1 & 2 & -1 & -6 \\ 0 & 1 & 1 & 1 \\ 0 & 0 & 1 & 3 \\ \end{array} \right] \Rarr \begin{cases} \begin{aligned} x_1 + 2 x_2 - x_3 &= -6 \\ x_2 + x_3 &= 1 \\ x_3 &= 3 \\ \end{aligned} \end{cases}

再运用加减消元法即可得到每个未知量的解,也可以进一步化简该矩阵:

[121601110013][120301020013][100101020013]\begin{aligned} & \left[ \begin{array}{ccc|c} 1 & 2 & -1 & -6 \\ 0 & 1 & 1 & 1 \\ 0 & 0 & 1 & 3 \\ \end{array} \right] \\ \Rarr& \left[ \begin{array}{ccc|c} 1 & 2 & 0 & -3 \\ 0 & 1 & 0 & -2 \\ 0 & 0 & 1 & 3 \\ \end{array} \right] \\ \Rarr& \left[ \begin{array}{ccc|c} 1 & 0 & 0 & 1 \\ 0 & 1 & 0 & -2 \\ 0 & 0 & 1 & 3 \\ \end{array} \right] \\ \end{aligned}

最后得到的矩阵名为「简化阶梯形矩阵」,它的系数矩阵部分是一个 nn 阶单位矩阵,也叫做「对角矩阵」。该矩阵直接给出了方程组的解。

#基本思想

对于每个未知量 xix_i,找到一个 xix_i 的系数非零、但 x1xi1x_1 \sim x_{i - 1} 的系数都是零的方程,然后使用初等行列变换将其他方程组 xix_i 的系数全部消成零,之后再逐一回代求解出所有未知量。

#方程组的解

消元后有以下几种情况:

  1. 完美阶梯形:存在唯一解;
  2. 含有系数全为零、常数不为零的行:无解;
  3. 含有系数和常数均为零的行:存在无穷多组解。

#算法实现

枚举系数矩阵中的每一列 cc

  1. 找到绝对值最大的一行;
  2. 将该行移至顶部;
  3. 将该行第 11 个非零的数变成 11
  4. 将下方所有行的第 cc 列变成 00

之后再将系数矩阵化为对角矩阵即可求出所有未知量的值。

#代码

a 数组中存储了表示线性方程组的增广矩阵。

C++
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
int gauss() {
int c, r;

for (c = 1, r = 1; c <= n; c++) {
// 找到绝对值最大的一行
int t = r;
for (int i = r; i <= n; i++) {
if (std::abs(a[i][c]) > std::abs(a[t][c])) t = i;
}

// 非零
if (std::abs(a[t][c]) < eps) continue;

// 将该行移至顶部
for (int i = c; i <= n + 1; i++) {
std::swap(a[t][i], a[r][i]);
}

// 将该行第一个非零的数变成 1
for (int i = n + 1; i >= c; i--) {
a[r][i] /= a[r][c];
}

// 将下方所有行的第 c 列变成 0
for (int i = r + 1; i <= n; i++) {
if (std::abs(a[i][c]) > eps) { // 非零
for (int j = n + 1; j >= c; j--) {
a[i][j] -= a[r][j] * a[i][c];
}
}
}

r++;
}

if (r <= n) {
for (int i = r; i <= n; i++) {
if (std::abs(a[i][n + 1]) > eps)
// 无解
return -1;
}

// 无穷多组解
return 1;
}

// 将系数矩阵化为对角矩阵
for (int i = n; i; i--) {
for (int j = i + 1; j <= n; j++) {
a[i][n + 1] -= a[i][j] * a[j][n + 1];
}
}

// 有解
return 0;
}

当函数返回 0 时方程组有解,返回 -1 时无解,返回 1 时有无穷多组解。

#参考资料

  1. 6.3.1 高斯消元法,《信息学奥赛之数学一本通》(ISBN 978-7-5641-6576-5,东南大学出版社),林厚从,2019 年 11 月第 9 次修订版。
  2. 高斯消元,第四章 数学知识,AcWing 算法基础课,闫学灿,2019 年 7 月 5 日。
  3. 0x35 高斯消元和线性空间,《算法竞赛进阶指南》(ISBN 978-7-83009-313-6,河南电子音像出版社),李煜东,2019 年 5 月第 5 次修订版。