前言
本文并不打算讨论任何关于高斯-约旦消元算法某一步的正确性以及为什么要那样做, 仅给出算法流程以及示例代码(Luogu高斯消元模板题)。
本文的判无唯一解方法可能是不完美的, 也绝对是不精细(无法区分无解和无穷多解)的。
高斯-约旦消元的作用:
同高斯消元。
解形如
[egin{cases}
a_{11}x_1 + a_{12}x_2 + dots + a_{1n}x_n = b_1\
a_{21}x_1 + a_{22}x_2 + dots + a_{2n}x_n = b_2\
vdots qquad qquad qquad ddots qquadqquad qquad vdots \
a_{n1}x_1 + a_{n2}x_2 + dots + a_{nn}x_n = b_n\
end{cases}
]
的线性方程组
一点扯淡
对于线性方程组有三种 “初等行变换”, 分别是
- 交换两行
- 将某行减去某行
- 将某行乘一个非零数
这三种 “初等行变换” 的共同特点是 不改变方程组的本质。
高斯-约旦消元 和 高斯消元 通过这三种 “初等行变换” 来解线性方程组。
消元过程与无唯一解的情况
过程:
共 (n) 步, 第 (i) 步选出 未被选过的行中 (x_i) 的系数最大的那一行, 运用初等行变换, 将其他所有行的 (x_i) 的系数变为 (0)。
(n) 步结束后, 可以直接得到方程组的解。
无唯一解的情况
若在某一步 (i) 中选出的 未被选过的行中 (x_i) 的系数最大的那一行的 (x_i) 的系数为 (0), 则无唯一解。
代码实现
这里选用的例题是Luogu的高斯消元模板题。
#include<bits/stdc++.h>
using namespace std;
#define db double
const int maxn = 135;
const db eps = 1e-13;
int n;
db a[maxn][maxn];
void fail() {
cout << "No Solution";
}
int main()
{
scanf("%d", &n);
for(int i=1;i<=n;++i) for(int j=1;j<=n+1;++j) scanf("%lf", &a[i][j]);
for(int i=1;i<=n;++i) {
int mx=i; for(int j=i+1;j<=n;++j)if(fabs(a[j][i])>fabs(a[mx][i])) mx=j;// 注意一定是绝对值最大, 具体可以思考+实践试错qwq
swap(a[i], a[mx]);// 似乎是通过交换指针实现交换行, 不过管他呢, 反正怎么交换复杂度都没有影响
if(fabs(a[i][i]) < eps) {fail(); return 0;}
for(int j=1;j<=n;++j) if(j^i) { // ((a^b)==1) == ((a!=b)==1)
// 将其他行消元
register db tmp = a[j][i]/a[i][i];
for(int k=i;k<=n+1;++k) a[j][k] -= a[i][k]*tmp;
}
}
for(int i=1; i<=n; ++i) printf("%.2lf
", a[i][n+1]/a[i][i]);
return 0;
}