前言
學了才發現這玩意賊簡單雖然據說是複習。
直接來
高斯消元用於解一個線性方程組,就是:
(其中是已知量)
我們接下來都用係數表達式(注意所有的與其他的含義有不同,但我們將它們放在一起):
高斯消元的目的是把原方程變成這樣:
那麼從下往上依次回代,就能得到所有的值了,代碼如下:
for(int i = N; i >= 1; i--) {
Ans[i] = A[i][N + 1];
for(int j = N; j >= i + 1; j--)
Ans[i] -= Ans[j] * A[i][j];
}
所以我們枚舉:將變爲(①),然後把全部變成(②)。
- 對於①操作,非常簡單,把第行的係數全部除以即可;
- 對於②操作,你要根據加減消元法,用第行的係數去把消爲,其他不管。那就給把變成(行其他係數按等式的性質依次變),再將第行的每個係數減掉。即:第行的每個係數都減去。
以上就是高斯消元的過程,自己照着代碼打一遍,模擬一下過程就能夠很好地理解了。
還有一個細節,我們每次在操作①和操作②之前把所在的那行跟第行換一個位置,可以減少精度誤差。
還有一個細節,判斷無解:若當前,那麼高斯消元就無法繼續了(操作②無法進行),且也不能確定,輸出No Solution
(但並不一定無解)。
代碼
#include <algorithm>
#include <cstdio>
#include <cstring>
#include <vector>
int Read() {
int x = 0;
char c = getchar();
while (c < '0' || c > '9')
c = getchar();
while (c >= '0' && c <= '9')
x = x * 10 + (c ^ 48), c = getchar();
return x;
}
const double eps = 1e-7;
inline double Abs(const double &x) {
return x < 0 ? -x : x;
}
inline int Comp(const double &x,const double &y) {
if (Abs(x-y) < eps)
return 0;
return Abs(x) > Abs(y) ? 1 : -1;
}
const int MAXN = 100;
int N;
double A[MAXN + 5][MAXN + 5], Ans[MAXN + 5];
int main() {
N = Read();
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 pos = i;
for(int j = i + 1; j<= N; j++)
if(Comp(A[j][i], A[pos][i]) == 1)
pos = j;
// 這裏找A[j][i]最大的是爲了減少精度誤差 與算法正確性無關
if(Comp(A[pos][i], 0) == 0) {
puts("No Solution");
return 0;
}
for(int j = 1; j <= N + 1; j++)
std::swap(A[pos][j], A[i][j]);
// 把A[j][i]最大的那行換上去
double tmp = A[i][i];
for(int j = i; j <= N + 1; j++)
A[i][j] /= tmp;
// 操作一
for(int j = i + 1; j <= N; j++){
tmp = A[j][i];
for(int k = i; k <= N + 1; k++)
A[j][k] -= A[i][k] * tmp;
}
// 操作二
}
for(int i = N; i >= 1; i--) {
Ans[i] = A[i][N + 1];
for(int j = N; j >= i + 1; j--)
Ans[i] -= Ans[j] * A[i][j];
}
for(int i = 1; i <= N; i++)
printf("%.2f\n", Ans[i]);
return 0;
}