高斯-约旦消元法 复习笔记
前言
没有什么意外,发现学过的东西又忘了。
我真的是 AH 第一没脑子选手。
正题
相对于传统的高斯消元,约旦消元法的精度更好、代码更简单,没有回带的过程。——某洛谷博客
算法流程
约旦消元法大致思路如下:
- 选择一个尚未被选过的未知数作为主元,选择一个包含这个主元的方程。
- 将这个方程主元的系数化为1。
- 通过加减消元,消掉其它方程中的这个未知数。
- 重复以上步骤,直到把每一行都变成只有一项有系数。
算法验证
先随便列一个方程组:
\[\begin{cases}
3x+y+3z=6\\
-2x+7y+8z=17\\
9x-7y+2z=20\\
\end{cases}
\]
用 高斯-约旦消元 的方法接触当前方程的解。
- 先把方程组转化成为矩阵的形式。
以上文的方程组为例,我们列出这样的一个矩阵:
\[\begin{bmatrix}
3 & 1 & 3 & 6\\
-2& 7 & 8 & 17\\
9 &-7 & 2 & 20\\
\end{bmatrix}
\]
- 看第一列,从上到下扫描,发现绝对值更大的就直接交换。
\[\begin{bmatrix}
3 & 1 & 3 & 6\\
-2& 7 & 8 & 17\\
9 &-7 & 2 & 20\\
\end{bmatrix}
\rightarrow
\begin{bmatrix}
9 &-7 & 2 & 20\\
-2& 7 & 8 & 17\\
3 & 1 & 3 & 6\\
\end{bmatrix}
\]
- 然后运用消元的办法消元就可以了捏。(太懒了不想再算这种申必的系数)
- 之后的直接重复上面的两步就可以了。
最后会变成一个类似这样的东西:
\[\begin{bmatrix}
a_{1,1} &0 & 0 & a\\
0& a_{2,2} & 0 & b\\
0 & 1 & a_{3,3} & c\\
\end{bmatrix}
\]
直接算就好了。
注意:当出现有一列全部为零时,说明无解。
Code
#include <bits/stdc++.h>
#define file(a) freopen(a".in", "r", stdin), freopen(a".out", "w", stdout)
#define Enter putchar('\n')
#define quad putchar(' ')
#define N 1005
int n;
double a[N][N];
signed main(void) {
// file("P3389");
std::cin >> 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 maxn = i;
for (int j = i + 1; j <= n; j++)
if (fabs(a[j][i]) > fabs(a[maxn][i])) maxn = j;
for (int j = 1; j <= n + 1; j++)
std::swap(a[i][j], a[maxn][j]);
if (!a[i][i]) {printf("No Solution\n"); return 0;}
for (int j = 1; j <= n; j++) {
if (j == i) continue;
double tmp = a[j][i] / a[i][i];
for(int k= i + 1; 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]);
}