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

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/wljoi/article/details/102709616

前置知识

高斯消元

逆矩阵定义

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

实现

前置:单位矩阵( E E )

单位矩阵的定义:

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

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

前置:矩阵的初等变换

定义矩阵的初等变换:

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

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

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

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

前置:初等矩阵

初等矩阵的定义:

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

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

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

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

矩阵求逆

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

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

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

我们在等式两边同时乘上 A A 的逆矩阵 A 1 A^{-1} ,那么我们有:
P 1 × P 2 × . . . × P n = A 1 P_1\times P_2\times ...\times P_n=A^{-1}
所以我们可以构造一个单位矩阵,在使用高斯消元将 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");
	}
}

猜你喜欢

转载自blog.csdn.net/wljoi/article/details/102709616
今日推荐