题解 【模板】矩阵求逆
原题链接:Link
前言
做完 Gauss消元 后在来尝试这一道题 ...
然后因为直接使用了那题的板子而吃了很多亏 ...
劝大家不要直接把那一题板子搬过来调,细节还是有很大不同的 ...
前置芝士
1.逆矩阵
设 \(A\) 是数域上的一个 \(n\) 阶矩阵,若在相同数域上存在另一个 \(n\) 阶矩阵 \(B\) ,使得: \(A*B=B*A=T\) ,则我们称 \(B\) 是 \(A\) 的逆矩阵,而 \(A\) 则被称为可逆矩阵。
上文来自百度词条,笔者语文不是很好所以直接复制下来,上文还是很容易懂的。
2.Gauss消元
【模板】高斯消元法:Link
这边笔者用的是 高斯-约旦消元法 。
这个相对于 高斯消元 没有回带的过程,因此代码也相对简单。那还要高斯消元干什么
普通的 高斯消元(这是【模板】高斯消元法 的解法,因此会用到浮点数的计算):
for(int i=1;i<=n;i++){
int t=i;
for(int j=i+1;j<=n;j++){
if(fabs(a[t][i])<fabs(a[t][i])){
t=j;
}
}
if(fabs(a[t][i])<0.0000001){
printf("No Solution");
return 0;
}
if(i!=t){
for(int j=1;j<=n+1;j++){
swap(a[i][j],a[t][j]);
}
}
double tmp=a[i][i];
for(int j=i;j<=n+1;j++){
a[i][j]/=tmp;
}
for(int j=i+1;j<=n;j++){
tmp=a[j][i];
for(int k=i;k<=n+1;k++){
a[j][k]-=a[i][k]*tmp;
}
}
ans[n]=a[n][n+1];
for(int i=n-1;i>=1;i--){
ans[i]=a[i][n+1];
for(int j=i+1;j<=n;j++){
ans[i]-=(map[i][j]*ans[j]);
}
}//这就是特殊的回带操作了
}
高斯-约旦消元:
for(int i=1;i<=n;i++){
int t=i;
for(int j=i+1;j<=n;j++){
if(fabs(a[j][i])>fabs(a[t][i])){
t=j;
}
}
for(int j=1;j<=n+1;j++){
swap(a[i][j],a[t][j]);
}
if(!a[i][i]){
cout<<"No Solution";
return 0;
}
for(int j=1;j<=n;j++){
if(j!=i){
double t=a[j][i]/a[i][i];
for(int k=i+1;k<=n+1;k++){
a[j][k]-=a[i][k]*t;
}
}
}
}
相比是不是 高斯-约旦消元 更胜一筹?
解题思路
在读入的 \(n\) 阶矩阵右侧加入一个 \(n\) 阶矩阵,然后做高斯消元,使读入的 \(n\) 阶矩阵化为 \(n\) 阶单位矩阵,此时右面加入的矩阵就为所求的逆。
所以这题就是主要就是 求逆矩阵+高斯消元 。
上文已经介绍了 逆矩阵 与 高斯消元。
具体就是这样,细节看代码。
#include<bits/stdc++.h>
#define int long long
using namespace std;
const int mod=1e9+7;
int a[410][810];
signed wyxakioi(int x,int y){
int p=1;
while(y){
if(y%2==1){
p=(p*x)%mod;
}
x=x*x%mod;
y/=2;
}
return p%mod;
}//求逆元
signed main(){
int n;
cin>>n;
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
cin>>a[i][j];
a[i][i+n]=1;//构造右侧矩阵
}
}
for(int i=1;i<=n;i++){
int t=i;
for(int j=i+1;j<=n;j++){
if(abs(a[j][i])>abs(a[t][i])){
t=j;
}
}
if(i!=t){
for(int j=1;j<=n*2;j++){
swap(a[i][j],a[t][j]);
}
}
if(!a[i][i]){
cout<<"No Solution";
return 0;
}
int iee=wyxakioi(a[i][i],mod-2);//得出逆元
for(int j=1;j<=n;j++){
if(j!=i){
int tmp=a[j][i]*iee%mod;
for(int k=i;k<=n*2;k++){
a[j][k]=((a[j][k]-a[i][k]*tmp)%mod+mod)%mod;
}
}
}//上面就是基本 高斯-约旦消元 的板子的,就是多了一个逆元的处理。
for(int j=1;j<=n*2;j++){
a[i][j]=(a[i][j]*iee%mod);
}//这边还要注意多处理一步
}
for(int i=1;i<=n;i++){
for(int j=n+1;j<=n*2;j++){
cout<<a[i][j]<<" ";
}
cout<<endl;
}
return 0;
}
具体就是这样,有什么不懂还可以私信我。
管理员审核辛苦了!
不管多么痛苦,都不要逃往轻松的那一边。
浙公网安备 33010602011771号