高斯消元(求解n元一次方程组)

一.高斯消元的求解线性方程组

1. 问题:给定一个n元一次方程组,如何判断解的情况,以及求出解?

2.方法:高斯消元

如果是我们人,我们自然会消元法来消元,通过将某个多元一次方程化为一元一次方程,求出结果。

我们定义第i行(第i个方程)为Ri
那么消元的过程就相当于以下三种操作:
1.交换Ri与Rj
2.Ri乘以常数k
3.Ri加上(Rj乘以常数k)
其实就是线性代数中的初等行变化
高斯消元的思路就是化为以下形式的矩阵(首非0元为1的阶梯矩阵)
1 a b c
0 1 d e
0 0 1 g

这样就可以倒着回代求出所有解了

如何化成该矩阵呢?
步骤如下:
1.一行一行处理,(假设处理到第i行)
2.check:判断第i行元素是否有非0元素
3.将首非0元素变为1,(j就是第i行的第i个元素),并处理该行其他元素
4.用第i行去将该“1”所在列后面的其他元素消为0
【注意1】check,因为若方阵元素均为0,解元素不为0,则方程无解:若方阵元素和解元素均为0,则方程有无穷多解。
【注意2】由于过程中会损失精度,所以我们通常会给定一个精度eps,当元素值小于eps时,将其视为0

3.代码实现

#include<bits/stdc++.h>
using namespace std;
double a[105][105],x[105];
double eps=1e-7;
int n;

void check(int i){
    
    //判断是否无解或有无穷多解 
	int maxj=i;
	for(int j=i+1;j<=n;j++){
    
    
		if(fabs(a[i][maxj])<fabs(a[i][j]))maxj=j;
	}
	if(fabs(a[i][maxj])<eps){
    
    
		cout<<"No Solution";
		exit(0);
	}
}
int 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++){
    
    //处理第i行 
		
		check(i);//判断是否无解或有无穷多解 
		 
		double div=a[i][i];
		for(int j=i;j<=n+1;j++)a[i][j]/=div;//更改当前行,将第i行第i个元素变为1,(第i个之前的元素已经为0) 
		
		for(int k=i+1;k<=n;k++){
    
    //更改其他行信息 
		    div=a[k][i];//本质是a[k][i]/a[i][i],且a[i][i]=1 
			for(int j=i;j<=n+1;j++){
    
    //将第k行第j个元素变为0  
				a[k][j]-=div*a[i][j];
			}
		}
	}
	
    //最后矩阵的样子大概如下
	//1abcd
	//01efg
	//001hi
	//0001j 
    x[n]=a[n][n+1]; 
	for(int i=n-1;i>=1;i--){
    
    //回代求解 
		x[i]=a[i][n+1];
		for(int j=i+1;j<=n;j++)x[i]=x[i]-a[i][j]*x[j];
	}
    
    for(int i=1;i<=n;i++)printf("%.2lf\n",x[i]); 
	return 0;
}

模板题

二.高斯消元求逆矩阵

1.问题:给定n阶方阵,判断矩阵是否可逆,并求其mod p下的逆矩阵

2.方法:高斯消元

仍然用初等行变化进行求解
设求解的矩阵为A,单位矩阵E
结论:(A,E)->(E,A-1
那么问题就转化为,如何将一个A转化为E
步骤如下:
1.一行一行处理,(假设处理到第i行)
2.通过交换两行使得第i行首元非0
3.将首非0元素变为1,(j就是第i行的第i个元素),并处理该行其他元素,ps:因为这涉及除法,所以要求逆元
4.用第i行去将该“1”所在其他列的其他元素消为0
【注意】若在求解的过程中无法实现第二步,则矩阵不可逆

矩阵最后会变成这个样子
100abc
010deg
001hkp
右边就是该矩阵的逆矩阵

3.代码实现

#include<bits/stdc++.h>
using namespace std;

const int N=405;
const long long p=1e9+7;
int n,m;
long long a[N][N<<1];
long long ksm(long long a,long long b) {
    
     //求逆元
	ret=1;
	while(b) {
    
    
		if(b&1)ret=ret*a%p;
		a=a*a%p;
		b>>=1;
	}
	return ret;
}

int main() {
    
    
	cin>>n;
	m=n*2;
	for(int i=1; i<=n; ++i) {
    
    
		for(int j=1; j<=n; j++) {
    
    
			cin>>a[i][j];
		}
		a[i][n+i]=1;//矩阵右边构造一个单位矩阵
	}
	for(int i=1; i<=n; i++) {
    
     //高斯消元板子
		for(int k=i; k<=n; k++) {
    
    //保证首非0元素不为0 
			if(a[k][i]) {
    
    
				for(int j=1; j<=m; j++)swap(a[i][j],a[k][j]);
				break;
			}
		}
		if(!a[i][i]) {
    
    //若首非0元素为0,则矩阵无解 
			cout<<"No Solution";
			return 0;
		}
		long long x=ksm(a[i][i],p-2);  //求逆元
		for(int j=i; j<=m; j++)a[i][j]=a[i][j]*r%p;//更改当前行
		for(int k=1; k<=n; k++) {
    
     //更改其他行信息
			if(k!=i) {
    
    
				long long div=a[k][i];
				for(int j=i; j<=m; j++)a[k][j]=(a[k][j]-div*a[i][j]%p+p)%p;
			}
		}
	//最后的矩阵的样子大概如下
	//100abc
	//010def
	//001ghi 
	}
	for(int i=1; i<=n; i++) {
    
    
		for(int j=n+1; j<=m; j++){
    
    
			cout<<a[i][j]<<" ";
		}
		cout<<endl;
	}

	return 0;
} 

猜你喜欢

转载自blog.csdn.net/weixin_43602607/article/details/111935577
今日推荐