一.高斯消元的求解线性方程组
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;
}