← 返回首页

高斯消元:从线性方程组到矩阵求根,手把手搞定解法

高斯消元:从线性方程组到矩阵求根,手把手搞定解法
高斯消元:从线性方程组到矩阵求根,手把手搞定解法

1. 引言

想象你面前有一张纸,上面写着:

$$

\begin{cases}

2x + y - z = 8 \

-3x - y + 2z = -11 \

-2x + y + 2z = -3

\end{cases}

$$

这就是一个三元一次方程组。手算可能容易出错?高斯消元法就像给方程组做「手术」——通过初等行变换(交换、倍乘、加减),将增广矩阵化为上三角阶梯形,再回代求解。竞赛中遇到「线性方程组」「模意义下求逆」「行列式计算」等问题,掌握高斯消元就是降维打击(如洛谷P3389直接送分)。


2. 核心概念讲解

目标与步骤

核心思想:通过消元将方程组转化为阶梯形,再回代求解。

关键步骤:

  1. 选主元(Partial Pivoting)

每步选择当前列中绝对值最大的行作为主元,避免除零和精度爆炸(尤其实数域)。

  1. 消元(Forward Elimination)

用主元所在行的倍数消去下方所有行的对应列元素(类似“等式两边同乘”操作)。

  1. 回代(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$的线性方程组,判断是否有唯一解并输出。

思路

  1. 直接套用代码框架,注意主元为0时跳过。

  2. 消元后若出现[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. 推荐练习

  1. 洛谷P3389 高斯消元法 (必刷)

  2. 洛谷P1083 车站分级 (实际应用题,需先化简方程组)

  3. CF 16E Gauss Tower (进阶应用,涉及矩阵性质)


7. 扩展预告

下期我们将深入讨论:

  • 模意义下高斯消元(处理大质数模下的线性方程组)

  • 分数运算优化(避免浮点误差)

  • 稀疏矩阵优化技巧


💡 小贴士:高斯消元的核心是“化简+回代”,理解每一步的数学本质比死记硬背更重要!