1. 引言
想象你面前有一张纸,上面写着:
$$
\begin{cases}
2x + y - z = 8 \
-3x - y + 2z = -11 \
-2x + y + 2z = -3
\end{cases}
$$
这就是一个三元一次方程组。手算可能容易出错?高斯消元法就像给方程组做「手术」——通过初等行变换(交换、倍乘、加减),将增广矩阵化为上三角阶梯形,再回代求解。竞赛中遇到「线性方程组」「模意义下求逆」「行列式计算」等问题,掌握高斯消元就是降维打击(如洛谷P3389直接送分)。
2. 核心概念讲解
目标与步骤
核心思想:通过消元将方程组转化为阶梯形,再回代求解。
关键步骤:
- 选主元(Partial Pivoting)
每步选择当前列中绝对值最大的行作为主元,避免除零和精度爆炸(尤其实数域)。
- 消元(Forward Elimination)
用主元所在行的倍数消去下方所有行的对应列元素(类似“等式两边同乘”操作)。
- 回代(Back Substitution)
从最后一行开始,逐层向上代入求解。
图示解释:
初始增广矩阵:
$$
\left[\begin{array}{ccc|c}
2 & 1 & -1 & 8 \
-3 & -1 & 2 & -11 \
-2 & 1 & 2 & -3
\end{array}\right]
$$
消元后目标(上三角):
$$
\left[\begin{array}{ccc|c}
- & * & * & * \
0 & * & * & * \
0 & 0 & * & *
\end{array}\right]
$$
3. C++代码示例(完整可运行)
#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
const double EPS = 1e-8; // 浮点误差阈值
// 高斯消元主函数(支持n×m非方阵,返回true表示有唯一解)
bool gauss(vector<vector<double>>& A, vector<double>& res) {
int n = A.size(); // 方程个数
int m = A[0].size() - 1; // 未知数个数(最后一列为常数项)
for (int col = 0, row = 0; col < m && row < n; ++col) {
// 1. 选主元(Partial Pivoting)
int pivot = row;
for (int i = row + 1; i < n; ++i)
if (fabs(A[i][col]) > fabs(A[pivot][col]))
pivot = i;
if (fabs(A[pivot][col]) < EPS) continue; // 无主元→多解/无解
swap(A[row], A[pivot]); // 交换行
// 2. 消元
for (int i = row + 1; i < n; ++i) {
double factor = A[i][col] / A[row][col];
for (int j = col; j <= m; ++j)
A[i][j] -= factor * A[row][j];
}
++row;
}
// 3. 检查解的存在性
if (row < n) { // 存在自由变量或有矛盾
for (int i = row; i < n; ++i)
if (fabs(A[i][m]) >= EPS) return false; // 矛盾方程→无解
return true; // 自由变量→无穷多解(本例不处理,仅返回唯一解标志)
}
// 4. 回代
res.resize(m);
for (int i = n - 1; i >= 0; --i) {
res[i] = A[i][m];
for (int j = i + 1; j < m; ++j)
res[i] -= A[i][j] * res[j];
res[i] /= A[i][i];
}
return true;
}
int main() {
int n, m; // 方程个数与未知数个数
cin >> n >> m;
vector<vector<double>> A(n, vector<double>(m + 1)); // 增广矩阵(系数+常数项)
for (int i = 0; i < n; ++i)
for (int j = 0; j <= m; ++j)
cin >> A[i][j];
vector<double> res;
if (gauss(A, res)) {
cout << "唯一解为: ";
for (auto x : res) printf("%.6f ", x);
cout << endl;
} else {
cout << "方程组无解或有无穷多解" << endl;
}
return 0;
}
注释说明
A[i][j]存储第i个方程第j个变量的系数,A[i][m]为常数项。使用
vector替代原生数组,避免越界问题。主元选取时用绝对值比较,确保数值稳定性。
回代顺序必须从最后一行开始。
4. 算法分析
时间复杂度:$O(n^3)$,适合$n \leq 100$(竞赛常用)。
空间复杂度:$O(n^2)$,存储增广矩阵。
局限性:
实数域下舍入误差可能导致结果不准(竞赛中多用整数或分数)。
若矩阵不满秩(如
[[1,1],[2,2]]),需特殊处理无解/多解情况。
5. 经典例题
洛谷P3389 [模板]高斯消元法
题目:给定$n \times n$的线性方程组,判断是否有唯一解并输出。
思路:
直接套用代码框架,注意主元为0时跳过。
消元后若出现
[0 ... 0 | c]且$c \neq 0$则无解;若存在全零行则多解。
AC代码关键点:
if (row < n) { // 未消完所有行
for (int i = row; i < n; ++i)
if (fabs(A[i][m]) > EPS) return false; // 无解
return true; // 多解(本题不要求输出)
}
6. 推荐练习
洛谷P3389 高斯消元法 (必刷)
洛谷P1083 车站分级 (实际应用题,需先化简方程组)
CF 16E Gauss Tower (进阶应用,涉及矩阵性质)
7. 扩展预告
下期我们将深入讨论:
模意义下高斯消元(处理大质数模下的线性方程组)
分数运算优化(避免浮点误差)
稀疏矩阵优化技巧
💡 小贴士:高斯消元的核心是“化简+回代”,理解每一步的数学本质比死记硬背更重要!