题解 【模板】矩阵求逆

原题链接: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;
}

具体就是这样,有什么不懂还可以私信我。

管理员审核辛苦了!

posted @ 2020-03-07 12:08  Kriraya  阅读(530)  评论(0)    收藏  举报