高斯消元法,高斯约旦消元法,线性方程组,矩阵求逆

这里说的主元是主对角线的上的元素。

求解线性方程组

高斯消元法

对于矩阵:
[ . . . . . . . . . ] \begin{bmatrix} .&.&.\\ .&.&.\\ .&.&. \end{bmatrix} .........

做初等行变换:

  1. 一行同乘一个实数
  2. 用一行加减另一行
  3. 交换两行

因而有了高斯消元法,可以把一个方阵消为上三角矩阵。或者把一个矩阵的靠左的元素构成的方阵消为上三角矩阵。

对于方程组:
I i = 1 n { ∑ j = 1 n a i , j x j = b i \overset{n}{{\underset{i=1}{\mathbb{I}}}}\left\{\begin{matrix} {\overset{n}{\underset{j=1}\sum}} a_{i,j}x_j=b_i \end{matrix}\right. i=1In{j=1nai,jxj=bi
可以写成三个矩阵的乘积:

系数矩阵: A = I i = 1 n ↓ [ I j = 1 n a i , j → ] A=\overset{n}{{\underset{i=1}{\mathbb{I}}}}\downarrow{\begin{bmatrix} \overset{n}{{\underset{j=1}{\mathbb{I}}}}\underrightarrow{a_{i,j}} \end{bmatrix}} A=i=1In[j=1In ai,j]

未知量矩阵: X = I i = 1 n ↓ [ x i ] X=\overset{n}{{\underset{i=1}{\mathbb{I}}}}\downarrow{\begin{bmatrix} x_i\end{bmatrix}} X=i=1In[xi]

常数矩阵: B = I i = 1 n ↓ [ b i ] B=\overset{n}{{\underset{i=1}{\mathbb{I}}}}\downarrow{\begin{bmatrix} b_i\end{bmatrix}} B=i=1In[bi]

就有了:

A × X = B A\times X=B A×X=B

我们把系数矩阵和常数矩阵拼接起来,就得到了增广矩阵:
F = I i = 1 n ↓ [ ( I j = 1 n a i , j → ) b i ] F=\overset{n}{{\underset{i=1}{\mathbb{I}}}}\downarrow{\begin{bmatrix} \left( \overset{n}{{\underset{j=1}{\mathbb{I}}}}\underrightarrow{a_{i,j}}\right)&b_i \end{bmatrix}} F=i=1In[(j=1In ai,j)bi]

对增广矩阵做初等行变换,等价于对原线性方程组进行操作。

高斯消元法的主要过程是:

  1. 顺序枚举主元,找到主元下面第一个不为0的元素(同一列内,包括主元)。
    找不到不为0的元素就不存在唯一解。
  2. 把这一行与主元所在的行交换。
  3. 整一行除以主元,把主元变成1。
  4. 用主元翻倍去减它下面的数,把下面的数变成0

最终得到一个左侧是上三角矩阵的增广矩阵,此时可以自底而上回带求解。

回带的过程中,我们先有 a n , n ⋅ x n = b n a_{n,n}\cdot x_n=b_n an,nxn=bn,得到 x n x_n xn,再把 x n x_n xn带入 a n − 1 , n − 1 ⋅ x n − 1 + a n − 1 , n ⋅ x n = b n − 1 a_{n-1,n-1}\cdot x_{n-1}+a_{n-1,n}\cdot x_n=b_{n-1} an1,n1xn1+an1,nxn=bn1得到 x n − 1 x_{n-1} xn1。依此类推…

时间复杂度O( n 3 n^3 n3)

高斯约旦消元法

高斯约旦消元法的过程与高斯消元法类似:

  1. 顺序枚举主元,找到主元下面第一个不为0的元素(同一列内,包括主元)。
    找不到不为0的元素即不存在唯一解。
  2. 把这一行与主元所在的行交换。
  3. 整一行除以主元,把主元变成1。
  4. 用主元翻倍去减同一列除了它本身的所有数,把同一列的所有数变成0。(除了主元)
#include<iostream>
#include<cstdio>
#include<cmath>
#include<algorithm>
using namespace std;
int n;
double a[105][105];
bool solve() {
	for(int i=1;i<=n;i++) {
		int f=i;
		while(f<=n&&fabs(a[f][i])<1e-5) f++;
		if(f==n+1) return false;
		swap(a[i],a[f]);
		for(int j=n+1;j>=i;j--) a[i][j]/=a[i][i];
		for(int j=1,k=i;j<=n;j++,k=i) 
			if(i^j)
				for(double t=a[j][i];k<=n+1;k++)
					a[j][k]-=a[i][k]*t;
	}
	return true;
}
int main() {
	cin>>n;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n+1;j++)
			cin>>a[i][j];
	if(solve()) 
		for(int i=1;i<=n;i++) 
			printf("%.2lf\n",a[i][n+1]);
	else
		cout<<"No Solution"<<endl;
}

时间复杂度O( n 3 n^3 n3)

判断有唯一解/有无穷多解/无解

线性方程组的解有三种情况:

  1. 有唯一解
  2. 有无穷多组解
  3. 无解

如果手动化简的话,容易发现,如果化简过程中出现了 0 ⋅ x i = k 0\cdot x_i=k 0xi=k的情况,如果 k = 0 k=0 k=0,那么 x i x_i xi可以取任何值,那么就是无穷多解。如果 k ≠ 0 k\not=0 k=0则显然无解。

那么首先把 F F F变为最简行阶梯形矩阵 F ′ F' F,此时对应的系数矩阵和常数矩阵为 A ′ , B ′ A',B' A,B,则容易证明:

  • R ( A ′ ) ≠ R ( B ′ ) R(A')\not=R(B') R(A)=R(B),则无解。(显然此时有 R ( A ′ ) > R ( B ′ ) R(A')>R(B') R(A)>R(B)
  • R ( A ′ ) = R ( B ′ ) < n R(A')=R(B')<n R(A)=R(B)<n,则有无穷多解。
  • R ( A ′ ) = R ( B ′ ) = n R(A')=R(B')=n R(A)=R(B)=n,则有唯一解

其中 R ( X ) R(X) R(X)表示矩阵 X X X的非零行数。

要睡觉太困了不写证明了。

主要代码就是把 F F F变成最简行阶梯形矩阵:

#include <bits/stdc++.h>
#include<algorithm>
using namespace std;
const int N=100;
long double a[N+5][N+5];
int n;
void swap_line(int x,int y) {
	for(int i=1; i<=n+1; i++)
		swap(a[x][i],a[y][i]);
}
void div_line(int x,long double val) {
	for(int i=1; i<=n+1; i++)
		a[x][i]/=val;
}
void add_line(int u,int v,long double k) {
	//v+=u*k
	for(int i=1; i<=n+1; i++)
		a[v][i]+=a[u][i]*k;
}
long double eps=1e-9;
signed main() {
	cin>>n;
	for(int i=1; i<=n; i++)
		for(int j=1; j<=n+1; j++) cin>>a[i][j];
	for(int i=1; i<=n; i++) {
		int x,y;
		for(int j=i;j<=n;j++)//第j列 
			for(int k=i;k<=n;k++)//第k行 
				if(abs(a[x=k][y=j])>eps)
					goto flag;
		break;
		flag:;
		swap_line(i,x);
		div_line(i,a[i][y]);
		for(int j=1; j<=n; j++)
			if(i^j&&abs(a[j][y])>eps)
				add_line(i,j,-a[j][y]);
	}
	int x=0,y=0;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n+1;j++)
			if(abs(a[i][j])>eps){
				x++;
				break;
			}
		for(int j=1;j<=n;j++)
			if(abs(a[i][j])>eps){
				y++;
				break;
			}
	}
	if(x!=y){
		cout<<-1;
		return 0;
	}
	else if(x<n){
		cout<<0;
		return 0;
	}
	for(int i=1; i<=n; i++)
		printf("x%d=%.2f\n",i,(float)a[i][n+1]);
	return 0;
}

矩阵求逆

定义 I I I为单位矩阵。对于方阵 A A A,若有 A × A − 1 = A − 1 × A = I A\times A^{-1}=A^{-1}\times A=I A×A1=A1×A=I,则称 A − 1 A^{-1} A1 A A A的逆矩阵。若不存在 A − 1 A^{-1} A1,则称方阵 A A A不可逆。

矩阵求逆,用高斯约旦消元法:
对于 A × A − 1 = I A\times A^{-1}=I A×A1=I,把 A A A I I I拼接起来,得到 ( A , I ) (A,I) (A,I),对 ( A , I ) (A,I) (A,I)做高斯约旦消元法,变为 ( I , A − 1 ) (I,A^{-1}) (I,A1),此时右边就是矩阵的逆。如果左侧出现全零列/行,说明矩阵不可逆。

证明较繁,我也不会:

根据理论,首先有矩阵 E E E使得 A × E = A ′ A\times E=A' A×E=A E E E等价于做若干次初等行变换。

显然初等行变换可逆。

因此有 I × E = A I\times E=A I×E=A,表示对单位矩阵做若干次初等行变换可以得到 A A A。如果得不到,说明不可逆。

由于 E E E也是一个矩阵,可以把变化矩阵 E E E分解成若干个一次初等行变换矩阵乘积的形式: E = E 1 × E 2 × . . . × E n E=E_1\times E_2\times ...\times E_n E=E1×E2×...×En

因而有: I × E 1 × E 2 × . . . × E n = A I\times E_1\times E_2\times ...\times E_n=A I×E1×E2×...×En=A
I = A × E 1 − 1 × E 2 − 1 × . . . × E n − 1 I=A\times E_1^{-1}\times E_2^{-1}\times ...\times E_n^{-1} I=A×E11×E21×...×En1
A − 1 = I × E 1 − 1 × E 2 − 1 × . . . × E n − 1 A^{-1}=I\times E_1^{-1}\times E_2^{-1}\times ...\times E_n^{-1} A1=I×E11×E21×...×En1

也就是说,只要对 A A A做初等行变换能够变回单位矩阵,则对单位矩阵再做这些初等行变换,就能得到逆矩阵。

对单位矩阵再作这些初等行变换,等价于把 A A A I I I拼接起来,一起变换。

QED.(底气不足的证明)

减少高斯消元和高斯约旦消元法误差的一种方法是,在一列中选取绝对值最大的数作为主元,防止大数除以小数,末尾被吃掉。

后记

于是皆大欢喜。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值