高斯消元学习笔记

高斯消元是一种用来求解线性方程组(多元一次方程组)的算法。

假设我们现在需要求解一个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学长

posted @ 2022-02-12 20:51  zhi_kong  阅读(58)  评论(0)    收藏  举报