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

前言
本文并不打算讨论任何关于高斯-约旦消元算法某一步的正确性以及为什么要那样做, 仅给出算法流程以及示例代码(Luogu高斯消元模板题)。
本文的判无唯一解方法可能是不完美的, 也绝对是不精细(无法区分无解和无穷多解)的。


高斯-约旦消元的作用:
同高斯消元。

解形如

\[\begin{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 \qquad\qquad \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\n", a[i][n+1]/a[i][i]);
	return 0;
}
posted @ 2020-04-26 14:36  xwmwr  阅读(385)  评论(0编辑  收藏  举报