【矩阵求逆】高斯消元拓展

前置知识

高斯消元

逆矩阵定义

对于两个矩阵 A , B A,B A,B,如果 A × B = E A\times B=E A×B=E(其中 E E E)为单位矩阵,那么我们称 B B B A A A的逆矩阵, A A A为可逆矩阵。

实现

前置:单位矩阵( E E E)

单位矩阵的定义:

一个从左上角到右下角的对角线(主对角线)的元素全部为 1 1 1,其余元素全部为 0 0 0的矩阵。

单位矩阵的性质: A × E = E × A = A A\times E=E\times A=A A×E=E×A=A(常用于矩阵快速幂)

前置:矩阵的初等变换

定义矩阵的初等变换:

1. 交 换 矩 阵 中 两 行 / 列 1.交换矩阵中两行/列 1./

2. 将 矩 阵 的 一 行 / 列 同 时 乘 一 个 非 零 数 k 2.将矩阵的一行/列同时乘一个非零数k 2./k

3. 将 矩 阵 的 一 行 / 列 乘 非 零 数 k 后 加 到 另 一 行 / 列 ( 注 意 是 加 到 ) 3.将矩阵的一行/列乘非零数k后加到另一行/列(注意是加到) 3./k/

容易看出,矩阵的初等变换是可逆的,并且其逆运算是同一种类型的初等变换。

前置:初等矩阵

初等矩阵的定义:

初等矩阵是指由单位矩阵经过一次初等变换得到的矩阵。初等矩阵的模样可以写一个3阶或者4阶的单位矩阵。

初等矩阵的性质:设 A A A是一个 m × n m\times n m×n的矩阵,那么对 A A A施行一次初等行变换,就等价于在 A A A的左边乘上一个相应的 m m m阶(即 m × m m\times m m×m)的初等矩阵 M M M(即 M × A M\times A M×A)。对 A A A施行一次初等列变换,其结果等价于在 A A A的右边乘以相应的 n n n阶初等矩阵 N N N(即 A × N A\times N A×N)。反之亦然。

对于相应矩阵的解释:如果单位矩阵 E E E做出一种初等变换得到的矩阵为 E ′ E' E,矩阵 B B B做出同样的变换得到的矩阵为 B ′ B' B,那么 B ′ = E ′ × B B'=E'\times B B=E×B

初等矩阵一定存在逆矩阵。

矩阵求逆

首先,由矩阵的初等变换可逆得:

如果 A A A存在逆矩阵,那么 A A A可以通过一些初等变换,化为单位矩阵 E E E,即:

P 1 × P 2 × . . . × P n × A = E P_1\times P_2\times ...\times P_n \times A=E P1×P2×...×Pn×A=E
证明需要用到行列式的相关知识,此处不予提及。

我们在等式两边同时乘上 A A A的逆矩阵 A − 1 A^{-1} A1,那么我们有:
P 1 × P 2 × . . . × P n = A − 1 P_1\times P_2\times ...\times P_n=A^{-1} P1×P2×...×Pn=A1
所以我们可以构造一个单位矩阵,在使用高斯消元将 A A A转化成单位矩阵是我们同时对该单位矩阵进行同样的操作,最后输出单位矩阵即可。

例题:传送门

解析:用刚才的方法操作就好,分数取模时要求出逆元。

Code
#include<bits/stdc++.h>
#define int long long
#define Mod 1000000007
using namespace std;
int f[405][805];
int ksm(int a,int b){
	int res=1;
	while(b){
		if(b&1)  res=res*a%Mod;
		a=a*a%Mod;
		b>>=1;
	}
	return res;
}
signed main(){
	int n;
	cin>>n;
	for(int i=1;i<=n;i++){
		for(int j=1;j<=n;j++){
			scanf("%lld",&f[i][j]);
		}
		f[i][i+n]=1;
	}
	for(int i=1;i<=n;i++){
		for(int j=i;j<=n;j++){
			if(f[j][i]){
				for(int k=1;k<=n*2;k++){
					swap(f[i][k],f[j][k]);
				}
				break;
			}
		}
		if(!f[i][i]){
			cout<<"No Solution\n";
			return 0;
		}
		int r=ksm(f[i][i],Mod-2);
		for(int j=i;j<=n*2;j++){
			f[i][j]=f[i][j]*r%Mod;
		}
		for(int j=1;j<=n;j++){
			if(j!=i){
				r=f[j][i];
				for(int k=i;k<=n*2;k++){
					f[j][k]=(f[j][k]-r*f[i][k]%Mod+Mod)%Mod;
				}
			}
		}
	}
	for(int i=1;i<=n;i++){
		for(int j=n+1;j<=n*2;j++){
			printf("%lld ",f[i][j]);
		}
		printf("\n");
	}
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值