1. 程式人生 > 其它 >【luogu P4783】【模板】矩陣求逆(高斯消元)

【luogu P4783】【模板】矩陣求逆(高斯消元)

【模板】矩陣求逆

題目連結:luogu P4783

題目大意

給你一個 n*n 的矩陣,要你求它的逆矩陣。

思路

也就是要找一個矩陣使得 \(AB=E\)\(E\) 就是單位矩陣)。

然後你考慮弄三種矩陣的初等行變換。
交換兩行。
某一行乘上 \(k\)
某一行加上某一行乘 \(k\)

然後你考慮通過變換讓 \(A\) 變成 \(E\),然後這些操作就交給 \(B\),也就可以把一個 \(E\) 變成我們要的 \(B\) 了。
然後就用類似高斯消元,判無解的方法也跟高斯消元一樣。

然後搞就好啦。

程式碼

#include<cstdio>
#include<algorithm>
#define ll long long
#define mo 1000000007

using namespace std;

const int N = 400 + 1;
int n;
struct node {
	ll a[N][N];
	
	void Swap(int x, int y) {
		for (int i = 1; i <= n; i++) swap(a[x][i], a[y][i]);
	}
	
	void Times(int x, ll k) {
		k = (k % mo + mo) % mo;
		for (int i = 1; i <= n; i++)
			a[x][i] = a[x][i] * k % mo;
	}
	
	void Mul(int x, int y, ll k) {
		k = (k % mo + mo) % mo;
		for (int i = 1; i <= n; i++)
			a[x][i] = (a[x][i] + a[y][i] * k % mo) % mo; 
	}
}A, B;

ll ksm(ll x, ll y) {
	ll re = 1;
	while (y) {
		if (y & 1) re = re * x % mo;
		x = x * x % mo; y >>= 1;
	}
	return re;
}

ll inv(ll x) {
	return ksm(x, mo - 2);
}

int main() {
	scanf("%d", &n);
	for (int i = 1; i <= n; i++)
		for (int j = 1; j <= n; j++)
			scanf("%lld", &A.a[i][j]);
	for (int i = 1; i <= n; i++) B.a[i][i] = 1;
	
	for (int i = 1; i <= n; i++) {
		for (int j = i + 1; j <= n; j++)
			if (A.a[j][i]) {
				A.Swap(i, j); B.Swap(i, j); break;
			}
		if (!A.a[i][i]) {
			printf("No Solution"); return 0;
		}
		ll x = A.a[i][i]; x = inv(x);
		A.Times(i, x); B.Times(i, x);
		for (int j = i + 1; j <= n; j++) {
			x = -A.a[j][i];
			A.Mul(j, i, x); B.Mul(j, i, x);
		}
	}
	for (int i = n; i >= 1; i--)
		for (int j = i + 1; j <= n; j++) {
			ll x = -A.a[i][j];
			A.Mul(i, j, x); B.Mul(i, j, x);
		}
	
	for (int i = 1; i <= n; i++) {
		for (int j = 1; j <= n; j++) printf("%lld ", B.a[i][j]);
		puts("");
	}
	
	return 0;
}