高斯-约旦消元方法(预览)

前言
本文并不打算讨论任何关于高斯-约旦消元算法某一步的正确性以及为什么要那样做, 仅给出算法流程以及示例代码(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;
}
原文地址:https://www.cnblogs.com/tztqwq/p/12777974.html