【luogu 3389】高斯消元

我們小學學過二元一次方程組,

\left\{ \begin{matrix} x + y = 3\\ x + 2y = 4 \end{matrix} \right

很明顯,我們用下面的方程減去上面的方程就能求出y,然後再回代第一個方程我們就能求出x,高斯消元也是基於這樣的思想。

\left\{ \begin{matrix} a_{11}x_1+a_{12}x_2+a_{13}x_3+...+a_{1n}x_n = b_1\\ a_{21}x_1+a_{22}x_2+a_{23}x_3+...+a_{2n}x_n = b_2\\ ...\\ a_{n1}x_1+a_{n2}x_2+a_{n3}x_3+...+a_{nn}x_n = b_n\\ \end{matrix} \right

我們可以將這個寫成增廣矩陣的形式

\left | \begin{matrix} a_{11} &a_{12}&...&a_{1n}&b_1\\ a_{21} &a_{22}&...&a_{2n}&b_2\\ ...\\ a_{n1} &a_{n2}&...&a_{nn}&b_n\\ \end{matrix} \right |

爲了求出解,我們只有化解爲上三角行列式,怎麼化簡呢可以這樣,可以這樣考慮,對於第 i 行來說,我們用第 i 行下面的每一行減去倍數關係使得第i行下面的每一行的第 i 列都爲0。

先不管係數,我們來看一下過程。

\left | \begin{matrix} a_{11} &a_{12}&...&a_{1n}&b_1\\ a_{21} &a_{22}&...&a_{2n}&b_2\\ ...\\ a_{n1} &a_{n2}&...&a_{nn}&b_n\\ \end{matrix} \right | \Rightarrow \left | \begin{matrix} a_{11} &a_{12}&...&a_{1n}&b_1\\ 0 &a_{22}&...&a_{2n}&b_2\\ ...\\ 0 &a_{n2}&...&a_{nn}&b_n\\ \end{matrix} \right | \Rightarrow \left | \begin{matrix} a_{11} &a_{12}&...&a_{1n}&b_1\\ 0 &a_{22}&...&a_{2n}&b_2\\ ...\\ 0 &0&...&a_{nn}&b_n\\ \end{matrix} \right |

我們取枚舉每一行,然後用每一行下面的行,減去這一行的倍數,就能化簡爲上三角行列式。

接下來怎麼求出方程的解呢,回代。

最後一行只有一個未知數的係數不爲0,一次除法就能得到方程的解了,倒數第二行只有兩個未知數係數不爲0,將最後一行的解帶入倒數第二行,就只剩下一個未知數,一次除法就能得到倒數第二行的解了,依次類推。

爲了提高精度,我們按第i行係數絕對值從大到小進行枚舉。

#include<bits/stdc++.h>
using namespace std;
const int maxn = 100 + 7;
const double eps = 1e-8;
typedef double matrix[maxn][maxn];
int guass_elimination(matrix A, int n) // 高斯消元
{
	int i, j, k, r;
	for(i = 0; i < n; i++) { // 消元
		r = i;
		for(j = i + 1; j < n; j++) if(fabs(A[j][i]) > fabs(A[r][i])) r = j;
		if(fabs(A[r][i]) < eps) return 0;  // 無解
		if(r != i) for(int j = 0; j <= n; j++) swap(A[i][j], A[r][j]);
		for(k = i + 1; k < n; k++) {
			double f = A[k][i] / A[i][i];
			for(j = i; j <= n; j++) A[k][j] -= f * A[i][j];
		}
	}
	for(i = n - 1; i >= 0; i--) {  // 回代
		for(j = i + 1; j < n; j++) {
			A[i][n] -= A[j][n] * A[i][j];
		}
		A[i][n] /= A[i][i];
	}
	return 1; 
}
int main()
{
	int n;
	matrix A;
	while(scanf("%d", &n) == 1) {
		for(int i = 0; i < n; i++) {
			for(int j = 0; j <= n; j++) {
				scanf("%lf", &A[i][j]);
			}
		}
		int flag = guass_elimination(A, n);
		if(flag == 0) printf("No Solution\n");
		else {
			for(int i = 0; i < n; i++) printf("%.2lf\n", A[i][n]);
		}
	}
	return 0;
}

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章