链接:P2455 [SDOI2006] 线性方程组 - 洛谷
把整个算法大体上分成几个部分(个人理解)
1:枚举每一列c;(即枚举x, y, z....的系数)
2: 找到每一列的最大值,之后为了方便操作,将最大值的这一行放到第r行
3: 然后将第r行的每个数都除以a[r][c]的系数,目的就是为了让a[r][c]的系数为1,方便后续消元
4: 保证后面的每一行的第c列都变成0,就是在消元;
5: 最后会形成一个类似上三角行列式的东西, 此时消元已经完成了;
6: 通过这个上三角行列式和矩阵迭代回去即可
举个列子
其实可以发现在草稿纸上的模拟就和初中学的解方程基本一样
当然以上是这个方程保证有解的情况,还有两种情况,无解和无限解,我们结合代码来研究
#include <iomanip>
#include <iostream>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int N = 110;
const double eps = 1e-6;
double a[N][N];
int n;
int gauss()
{
int r, c;
for(c = 0, r = 0; c < n; c ++) // 枚举每一列c
{
int t = r;
for(int i = r; i < n; i ++)
{
if(fabs(a[i][c]) > fabs(a[t][c])) t = i; // 找到每一列的最大值
}
if(fabs(a[t][c]) < eps) continue;
for(int i = c; i <= n; i ++) swap(a[t][i], a[r][i]); // 将最大值换到第r行
// 注意这里一定要从n枚举到c,不能反过来,否则a[r][c]会被提前覆盖
for(int i = n; i >= c; i --) a[r][i] /= a[r][c]; // 将枚举的这一列系数变为1
for(int i = r + 1; i < n; i ++)
{
if(fabs(a[i][c]) > eps)
{
//这里也要倒着枚举,原因同上
for(int j = n; j >= c; j --)
{
a[i][j] -= a[r][j] * a[i][c]; // 消元
}
}
}
r ++;
}
if(r < n)
{
for(int i = r; i < n; i ++)
{
if(fabs(a[i][n]) > eps) return 2; // 无解
}
return 1; // 无穷解
}
for(int i = n - 1; i >= 0; i --)
{
for(int j = i + 1; j < n; j ++)
{
a[i][n] -= a[i][j] * a[j][n];
}
}
return 0; // 有唯一解
}
int main()
{
cin >> n;
for(int i = 0; i < n; i ++)
{
for(int j = 0; j <= n; j ++)
{
cin >> a[i][j];
}
}
int t = gauss();
int cnt = 0;
if(t == 0)
{
for(int i = 0; i < n; i ++)
{
cout << "x" << ++ cnt << "=" << fixed << setprecision(2) << a[i][n] << '\n';
}
}
else if(t == 1) cout << 0 << '\n';
else cout << -1 << '\n';
return 0;
}
这里可以看到,当r < n时,方程要么无解,要么有无限解,那么是什么原因导致了r < n呢? 原因就在于有一项列(x, y, z)的系数全为0, 我们假设z的系数为0, 那么最后一行是不是 0 == 一个数, 当然如果这个数是非0的数,那么就说明无解,如果恰好是 0 == 0, 那么我们也无法确定这个z的值,这就导致了x, y也无法确定,也就是有无穷多个解.