代数余子式和伴随矩阵

入门之后的一篇文章。

啊啊啊这玩意学了我一整天!这什么菜狗啊!

一、代数余子式

\(n\) 阶方阵 \(A=(a_{i,j})\) 中,删去第 \(i\) 行和第 \(j\) 列后所留下的方阵的行列式称为 \(a_{i,j}\)余子式 \(M_{i,j}\),而 \(a_{i,j}\) 的代数余子式为 \(A_{i,j}=(-1)^{i+j}M_{i,j}.\)

代数余子式可以用来算行列式:

\[\det(A)=\sum_{c=1}^n a_{r,c}A_{r,c} \]

二、伴随矩阵

(一)、定义

真不是因为我懒,主要是这个矩阵我不太会用 markdown 画出来。懒得搜还不是懒

(二)、性质及求解方法

首先我们用高斯消元计算 \(A\) 的 rank,然后分情况讨论。

1.rank(A)=n

有这样一个公式:\(AA^{*}=|A|I\),那么可得 \(A^{*}=|A|A^{-1}\)

我们试着感性证明一波 \(AA^{*}=|A|I\)

首先我们根据左行乘右列,当左边的行序数和右边的列序数相等时,由一、代数余子式中的公式可知算出来就是 \(|A|\)

那么不相等的时候呢?相当于算的是:\(\sum_{c=1}^n a_{i,c}A_{r,c}(i\not=r)\),相当于计算将最初的方阵 \(A\) 的第 \(i\) 行换为第 \(r\) 行的方阵后,计算它的行列式,由于有两行相等,\(A\) 不满秩,行列式为 0,所以上面那个式子算出来就是 0。

2.rank(A)<n-1

显然此时删掉一行一列之后仍然不满秩,所以 \(A^*=O,\operatorname{rank}(A^{*})=0\)

3.rank(A)=n-1

麻烦的来了。

首先由 \(\operatorname{rank}(A)=n-1\) 可知 \(\dim\ker(A)=1\)。于是存在非零行向量和列向量 \(p,q\) 使得 \(pA=0,Aq=0\)\(p,q\) 可以高斯消元求出。(这里有点类似于高中数学求平面的法向量)

由于行列最后得出的结论类似,所以我们这里只以列为例讲解。

\(Aq=0,\dim\ker(A)=1,\operatorname{rank}(A^*)=1\)

可得 \(A*\) 的每一行都是第一行的若干倍数,又因为 \(\operatorname{rank}(A)<n\),所以 \(|A|=0\)

\(|A|=a_{1,1}A_{1,1}+a_{1,2}A_{1,2}+...+a_{1,n}A_{1,n}=0\)

\(a_{1,1}q_1+a_{1,2}q_2+...+a_{1,n}q_n=0\)

\(\dim\ker(A)=1\) 可知 \(\frac{A_{1,1}}{q_1}=\frac{A_{1,2}}{q_2}=...=\frac{A_{1,n}}{q_n}\)。(当然这里如果有0就不能写成分式形式,但是为了美观还是这么写)

那么行的结论同理可得:\(\frac{A_{1,1}}{p_1}=\frac{A_{2,1}}{p_2}=...=\frac{A_{n,1}}{p_n}\)

所以为了求出所有的 \(A_{i,j}\),我们需要找到 \(r,c\) 使得 \(p_r,q_c\not=0\),那么可得 \(A_{i,j}=\frac{p_{i}q_{j}}{p_rq_{c}}A_{r,c}\),至于 \(A_{r,c}\) 直接暴力 \(O(n^3)\) 求即可。

(三)、例题

题目大意:求方阵的余子式。

Vjudge

OpenJudge

差点就拿DDG的代码开拍了
//12252024832524
#include <bits/stdc++.h>
#define TT template<typename T>
using namespace std; 

typedef long long LL;
const int MAXN = 200;
const int MOD = 998244353;
int n;

LL Read()
{
	LL x = 0,f = 1;char c = getchar();
	while(c > '9' || c < '0'){if(c == '-')f = -1;c = getchar();}
	while(c >= '0' && c <= '9'){x = (x*10) + (c^48);c = getchar();}
	return x * f;
}
TT void Put1(T x)
{
	if(x > 9) Put1(x/10);
	putchar(x%10^48);
}
TT void Put(T x,char c = -1)
{
	if(x < 0) putchar('-'),x = -x;
	Put1(x); if(c >= 0) putchar(c);
}
TT T Max(T x,T y){return x > y ? x : y;}
TT T Min(T x,T y){return x < y ? x : y;}
TT T Abs(T x){return x < 0 ? -x : x;}

int qpow(int x,int y)
{
	int ret = 1;
	while(y){if(y & 1) ret = 1ll * ret * x % MOD;x = 1ll * x * x % MOD;y >>= 1;}
	return ret;
}

int tmp[MAXN][MAXN];
struct Matrix
{
	int n,a[MAXN][MAXN];
	
	Matrix(){memset(a,0,sizeof(a));}
	
	void Get(int x){n = x;for(int i = 0;i < n;++ i) for(int j = 0;j < n;++ j) a[i][j] = Read();}
	void print(){for(int i = 0;i < n;++ i)for(int j = 0;j < n;++ j) Put(a[i][j],j == (n-1) ? '\n' : ' ');}
	void Add(int r1,int r2,int k){for(int i = 0;i < n;++ i) a[r2][i] = (a[r2][i] + 1ll * a[r1][i] * k) % MOD;}
	void Mul(int r,int k){for(int i = 0;i < n;++ i) a[r][i] = 1ll * a[r][i] * k % MOD;}
	void Mul(int k){for(int i = 0;i < n;++ i) for(int j = 0;j < n;++ j) a[i][j] = 1ll * a[i][j] * k % MOD;}
	void Trans(){for(int i = 0;i < n;++ i) for(int j = i;j < n;++ j) swap(a[i][j],a[j][i]);}
	Matrix TransNd(){Matrix ret;ret.n = n;for(int i = 0;i < n;++ i) for(int j = 0;j < n;++ j) ret.a[i][j] = a[j][i];return ret;}
	
	int Det(bool ri = 1)//whether ruin the previous one
	{
		int ret = 1;
		if(!ri) for(int i = 0;i < n;++ i) for(int j = 0;j < n;++ j) tmp[i][j] = a[i][j];
		for(int i = 0;i < n;++ i)
		{
			if(!a[i][i]) for(int j = i+1;j < n;++ j) if(a[j][i]) {ret = -ret;swap(a[i],a[j]);break;}
			if(!a[i][i]) {ret = 0;break;}
			for(int j = i+1;j < n;++ j)
				if(a[j][i])
				{
					int mul = 1ll * a[j][i] * qpow(a[i][i],MOD-2) % MOD;
					for(int k = i;k < n;++ k) a[j][k] = ((a[j][k] - 1ll * mul * a[i][k]) % MOD + MOD) % MOD;
				}
			ret = 1ll * ret * a[i][i] % MOD;
		}
		if(!ri) for(int i = 0;i < n;++ i) for(int j = 0;j < n;++ j) a[i][j] = tmp[i][j];
		return (ret+MOD)%MOD;
	}
	
	int Rank(bool ri = 1)
	{
		int ret = n;
		if(!ri) for(int i = 0;i < n;++ i) for(int j = 0;j < n;++ j) tmp[i][j] = a[i][j];
		for(int i = 0;i < n;++ i)
		{
			if(!a[i][i]) for(int j = i+1;j < n;++ j) if(a[j][i]) {swap(a[i],a[j]);break;}
			if(!a[i][i]) {--ret;continue;}
			for(int j = i+1;j < n;++ j)
				if(a[j][i])
				{
					int mul = 1ll * a[j][i] * qpow(a[i][i],MOD-2) % MOD;
					for(int k = i;k < n;++ k) a[j][k] = ((a[j][k] - 1ll * mul * a[i][k]) % MOD + MOD) % MOD;
				}
		}
		if(!ri) for(int i = 0;i < n;++ i) for(int j = 0;j < n;++ j) a[i][j] = tmp[i][j];
		return ret;
	}
	
	Matrix inv(bool ri = 1)
	{
		if(!ri) for(int i = 0;i < n;++ i) for(int j = 0;j < n;++ j) tmp[i][j] = a[i][j];
		Matrix ret; ret.n = n; for(int i = 0;i < n;++ i) ret.a[i][i] = 1;
		for(int i = 0;i < n;++ i)
		{
			if(!a[i][i]) for(int j = i;j < n;++ j) if(a[j][i]) {swap(a[i],a[j]);swap(ret.a[i],ret.a[j]);break;}
			if(!a[i][i]) break;//impossible
			for(int j = 0;j < n;++ j)
				if((i^j) && a[j][i])
				{
					int mul = 1ll * a[j][i] * qpow(a[i][i],MOD-2) % MOD;
					for(int k = i;k < n;++ k) a[j][k] = ((a[j][k] - 1ll * mul * a[i][k]) % MOD + MOD) % MOD;
					ret.Add(i,j,MOD-mul);
				}
		}
		for(int i = 0;i < n;++ i) ret.Mul(i,qpow(a[i][i],MOD-2));//a[i][i] = 1;
		if(!ri) for(int i = 0;i < n;++ i) for(int j = 0;j < n;++ j) a[i][j] = tmp[i][j];
		return ret;
	}
	
	Matrix Getq(bool ri = 1)//Aq = 0, to get q
	{
		if(!ri) for(int i = 0;i < n;++ i) for(int j = 0;j < n;++ j) tmp[i][j] = a[i][j];
		Matrix ret; ret.n = n;
		for(int i = 0;i < n;++ i)
		{
			if(!a[i][i]) for(int j = i+1;j < n;++ j) if(a[j][i]) {swap(a[i],a[j]);break;}
			if(!a[i][i]) 
			{
				ret.a[i][0] = 1;
				for(int j = i-1;j >= 0;-- j) ret.a[j][0] = (MOD-a[j][i])%MOD;
				for(int j = i-1;j >= 0;-- j)
				{
					ret.a[j][0] = 1ll * ret.a[j][0] * qpow(a[j][j],MOD-2) % MOD; //a[j][j] = 1;
					for(int k = j-1;k >= 0;-- k) ret.a[k][0] = ((ret.a[k][0] - 1ll * ret.a[j][0] * a[k][j]) % MOD + MOD) % MOD;
				}
				break;
			}
			for(int j = i+1;j < n;++ j)
				if(a[j][i])
				{
					int mul = 1ll * a[j][i] * qpow(a[i][i],MOD-2) % MOD;
					for(int k = i;k < n;++ k) a[j][k] = ((a[j][k] - 1ll * mul * a[i][k]) % MOD + MOD) % MOD;
				}
		}
		if(!ri) for(int i = 0;i < n;++ i) for(int j = 0;j < n;++ j) a[i][j] = tmp[i][j];
		return ret;
	}
	
	Matrix Del(int r,int c)//delete row r & column c
	{
		Matrix ret; ret.n = n-1;
		for(int i = 0;i < n;++ i)
			for(int j = 0;j < n && (i^r);++ j)
				if(j^c)
					ret.a[i-(i>r)][j-(j>c)] = a[i][j];
		return ret;
	}
}A,B,p,q;

int main()
{
//	freopen(".in","r",stdin);
//	freopen(".out","w",stdout);
	for(int T = Read(),rk; T ;-- T)
	{
		A.Get(n = Read()); rk = A.Rank(0);
		if(rk == n)
		{
			B = A.inv(0);
			B.Mul(A.Det());
			B.Trans();
		}
		else if(rk < n-1)
		{
			for(int i = 0;i < n;++ i)
				for(int j = 0;j < n;++ j)
					putchar('0'),putchar(j == (n-1) ? '\n' : ' ');
			putchar('\n'); continue;
		}
		else
		{
			q = A.Getq(0);//Aq = 0
			p = ((A.TransNd()).Getq()).TransNd();//pA = 0
			int r = 0,c = 0;
			for(int i = 0;i < n;++ i) if(p.a[0][i]) {r = i;break;}
			for(int i = 0;i < n;++ i) if(q.a[i][0]) {c = i;break;}
			B.n = n;
			B.a[r][c] = ((r+c) & 1 ? MOD-1ll : 1) * A.Del(r,c).Det() % MOD;
			int iv = 1ll * qpow(p.a[0][r],MOD-2) * qpow(q.a[c][0],MOD-2) % MOD;
			for(int i = 0;i < n;++ i) 
				for(int j = 0;j < n;++ j)
					B.a[i][j] = 1ll * iv * p.a[0][i] % MOD * q.a[j][0] % MOD * B.a[r][c] % MOD;
		}
		for(int i = 0;i < n;++ i)
			for(int j = 0;j < n;++ j)
				Put((B.a[i][j] * ((i+j) & 1 ? -1 : 1) + MOD) % MOD,j == (n-1) ? '\n' : ' ');
		putchar('\n');
	}
	return (0-0);
}
posted @ 2022-01-26 16:48  皮皮刘  阅读(2442)  评论(0编辑  收藏  举报