1. 程式人生 > 其它 >高斯消元學習筆記

高斯消元學習筆記

高斯消元是一種用來求解線性方程組(多元一次方程組)的演算法。

假設我們現在需要求解一個n元一次方程:

\(\begin{cases} a_{1,1}x_1+a_{1,2}x_2+...+a_{1,n}x_n=b_1 \\ a_{2,1}x_1+a_{2,2}x_2+...+a_{1,n}x_n=b_2 \\ \vdots \\ a_{n,1}x_1+a_{n,2}x_2+...+a_{1,n}x_n=b_n \\ \end{cases}\)

把係數存下來。

\(\begin{bmatrix}a_{1,1}&a_{1,2}&\cdots&a_{1,n}&b_1\\\vdots&\ddots&\vdots\\a_{n,1}&a_{n,2}&\cdots&a_{n,n}&b_n\end{bmatrix}\)

然後我們就可以進行高斯消元了,具體方法是:

\(step 1\)

列舉每一行,

​ 1.將第i行到第n行中第i列數的絕對值最大的數所在行與當前的第i行交換,防止當前行的第i列為0,消元無法 進行。
​ 2.用第i行的數乘上某個數去消其它行的數,使他們第i列變為0 。

​ 具體實現為:用第i行去消第j行,令\(x=a_{j,i}/a_{i,i}\),對於第j行的第k個數使\(a_{j,k}-=a_{i,k}*x\)

這樣,消元后的結果用矩陣表示出來就是一個階梯形的矩陣,第i行的元素有\(a_{i,i}\)~ \(a_{i,n}\)

\(step 2\)

現在我們最後一項只有一個未知數,所以我們從後往前列舉,每次求出一個未知數後,把該值分別代入前面的方程,再解前面一個方程,就能求出所有未知數。

在消元完成之後,一定為三種情況之一:

1.若存在係數全部為 0 但常數不為 0的項,方程組無解。

2.若係數不為 0 的行恰好有 n 個,說明方程恰好有 1個解。

3.若係數不為 0 的行有 k<n 個,說明主元有 k 個,自由元有 n−k 個,方程有無數多個解。

P3389 【模板】高斯消元法

#include<bits/stdc++.h>
using namespace std;
const int M=2005;
double a[M][M],ans[M],EPS=1e-7;
bool Free[M];
int n,m,rk;
bool Gauss(){
	int i,j;
	for(i=0,j=0;i<n&&j<m;i++,j++){
		
		int mx=i;
		for(int k=i+1;k<n;k++){
			if(fabs(a[k][j])>fabs(a[mx][j])) mx=k;
		}
		if(fabs(a[mx][j])<EPS){
			printf("No Solution");
			return 1;
		}
		if(mx!=i){
			for(int k=j;k<=m;k++){
				swap(a[i][k],a[mx][k]);
			}
		}
		for(int k=0;k<n;k++){
			if(k!=i&&fabs(a[k][j])>EPS){
				double x=a[k][j]/a[i][j];
				for(int u=m;u>=j;u--){
					a[k][u]-=x*a[i][u];
				}
			}
		}
	}
	rk=i;
	return 0;
}
int main(){
	scanf("%d",&n);
	m=n;
	for(int i=0;i<n;i++){
		for(int j=0;j<=n;j++){
			scanf("%lf",&a[i][j]);
		}
	}
	if(Gauss()){
		return 0;
	}
	for(int i=rk;i<n;i++){
		if(fabs(a[i][m])>EPS){
			printf("No Solution");
			return 0;
		}
	}
	if(rk<m){
		printf("No Solution");
		return 0;
	}
	for(int i=0;i<m;i++){
		Free[i]=1;
	}
	for(int i=rk-1;i>=0;i--){
		int cnt=0,pos;
		for(int j=0;j<m;j++){
			if(fabs(a[i][j])>EPS&&Free[j]){
				cnt++;pos=j;
			}
		}
		if(cnt==1){
			Free[pos]=0;
			ans[pos]=a[i][m]*1.0/a[i][pos];
		}
	}
	for(int i=0;i<n;i++){
		printf("%.2f\n", fabs(ans[i])<EPS?0:ans[i]);
	}
}

P4035 [JSOI2008]球形空間產生器
題目給了我們n+1個n元二次方程,無法直接使用高斯消元。
於是我們用第一個方程去減剩下的n個,得到了n個n元一次方程,直接套用高斯消元即可

帶狀矩陣

當求某些特殊問題(如概率dp,期望dp),矩陣係數矩陣為帶狀矩陣

例如:

我們每次沿對角線對一個\(d*d\) 的矩陣進行消元:

消完後還剩下:

然後回代即可。

所以消元為 \(O(nd^2)\),回代為\(O(nd)\)

總複雜度為 \(O(nd^2)\),d為頻寬。

圖片來源lsk學長