高斯消元
用于求解线性方程组。
[SDOI2006] 线性方程组
这里不放高斯消元板子是因为其中 No solution 情况分无穷组解和无解两种,没有这题这么详细。
题意:已知
其中任意的
回顾初中知识我们知道了加减消元的过程。具体而言我们会让方程组的某一元的系数一样或变为相反数从而用加减法去掉这一个元。例如这个:
我们让下面的式子
我们尝试模拟这个过程,具体而言:
- 枚举
1\to n ,我们找到x_i 最大的系数的那一个方程并把其与当前行交换。最大系数的原因是因为减少误差,详细证明看这里,由于笔者太菜就不证了。 - 我们用该方程消去其它方程的
x_i ,即乘上\frac{a_{j,i}}{a_{line,i}} ,然后用别的方程减去这个方程。这样最后的结果为仅剩当前方程含有x_i ,而别的x_i 系数都为0 。 - 最后我们就会得到一个只有
a_{i,i} 不为0 的方程组,x_i=\frac{a_{i,n+1}}{a_{i,i}} 。这是方程的唯一节,因为\frac{a_{i,n+1}}{a_{i,i}} 是固定的。
这个方法看似是很正确的,但是有一个必要前提:每次的元系数都不能为
举个例子:
如何判断到底是无穷多解还是无解?容易发现若
#include <bits/stdc++.h>
using namespace std;
const int _ = 55;
const double eps = 1e-9;
int n;
double a[_][_];
int Gauss() {
int line = 1;
for(int i = 1;i <= n;i++) {
int mx = line;
for(int j = line + 1;j <= n;j++) { //找到系数最大的行
if(fabs(a[j][i]) > fabs(a[mx][i])) mx = j;
}
if(fabs(a[mx][i]) < eps) continue; //若误差<1e-9则认为为 0
for(int j = 1;j <= n + 1;j++) swap(a[line][j],a[mx][j]);
for(int j = 1;j <= n;j++) { //消元其他的
if(line == j) continue;
double tmp = a[j][i] / a[line][i];
for(int k = i;k <= n + 1;k++) {
a[j][k] -= a[line][k] * tmp;
}
}
line++;
}
for(int i = line;i <= n;i++) {
if(fabs(a[i][n + 1]) > eps) { //若bi不为0
return -1;
}
}
return line > n;
}
int main() {
cin >> n;
for(int i = 1;i <= n;i++) {
for(int j = 1;j <= n + 1;j++) {
cin >> a[i][j];
}
}
int t = Gauss();
if(t == 1) {
for(int i = 1;i <= n;i++) {
cout << 'x' << i << '=' << fixed << setprecision(2) << a[i][n + 1] / a[i][i] << '\n';
}
} else {
cout << t << '\n';
}
return 0;
}
P3389 【模板】高斯消元法