[笔记]行列式

本文部分内容来自《高等代数》。


行列式定义

对于一个 n 阶行列式

An×n=|a11a12a1na21a22a2nan1an2ann|

其结果为所有不同行不同列的元素乘积的代数和。用数学语言写为:

j1j2jn(1)τ(j1j2jn)a1j1a2j2anjn

其中 j1j2jn1n 的一个排列。τ(j1j2jn) 表示排列 j 的逆序数的个数。

可以看出,如果 τ(j1jn) 为偶数,那么该排列对答案的贡献为正。否则为负。

行列式性质

《高代》里原本有七条性质,这里只证明有用的五条。

  • 性质一:行列式转置后值不变。即:

|a11a12a1na21a22a2nan1an2ann|=|a11a21an1a12a22an2a1na2nann|

  • 性质二:行列式内某一行的公因子可以提出。

|a11a12a1na21a22a2nkai1kai2kainan1an2ann|=k|a11a12a1na21a22a2nai1ai2ainan1an2ann|

证明:

首先考虑 n 级行列式的 n! 项。如果把他们分成 n 组,一定有一种方案,使得第 1 组中都含有 ai1,第 2 组中都含有 ai2,以此类推。如果第 j 项提出 aij 后记作 Aij,那么有

|a11a12a1na21a22a2nan1an2ann|

=ai1Ai1+ai2Ai2++ainAin=j=1naijAij

这将方便我们后面的讨论。

现在证明性质二:

|a11a12a1na21a22a2nkai1kai2kainan1an2ann|

=kai1Ai1+kai2Ai2++kainAin

=k(ai1Ai1+ai2Ai2++ainAin)

=k|a11a12a1na21a22a2nai1ai2ainan1an2ann|

  • 性质三:

|a11a12a1na21a22a2nb1+c1b2+c2bn+cnan1an2ann|

=|a11a12a1na21a22a2nb1b2bnan1an2ann|+|a11a12a1na21a22a2nc1c2cnan1an2ann|

证明:

原行列式可写成 (b1+c1)Ai1+(b2+c2)Ai2++(bn+cn)Ain,这等于右式。

  • 性质四:把第 k 行的倍数加到第 i 行,行列式不变。

证明太容易而公式又太难打,就不写了。

  • 性质五:对调行列式的两行,行列式反号。

证明:

|a11a12a1na21a22a2nai1ai2ainak1ak2aknan1an2ann|

=|a11a12a1na21a22a2nai1+ak1ai2+ak2ain+aknak1ak2aknan1an2ann|

=|a11a12a1na21a22a2nai1+ak1ai2+ak2ain+aknai1ai2ainan1an2ann|

=|a11a12a1na21a22a2nak1ak2aknai1ai2ainan1an2ann|

=|a11a12a1na21a22a2nak1ak2aknai1ai2ainan1an2ann|

其中第一步是利用性质四,将第 k 行加到了第 i 行上。

第二步是利用性质四,将第 i 行减去第 k 行。

第三步是利用性质四,将第 i 行加到了第 k 行上。

最后一步是利用性质二,将第 i 行提出 1

证毕。

特殊的行列式

  1. 对角行列式

形如
|a11000a22000ann|
的行列式称为对角行列式。其结果为 a11×a22ann

  1. 三角行列式

形如 |a11a12a1n0a22a2n000ann| 的行列式被称为三角行列式,其结果与对角行列式相同。

行列式计算

显然,如果按照定义,我们需要 O(n×n!) 的复杂度。显然无法接受。

由于存在一些特殊的行列式,可以考虑将原行列式转化为三角行列式后求值。思路就是将原行列式利用性质一到四进行转化。

例如有行列式 |235347432|,首先可以将 23 行分别加上第一行的 32,2 倍,化为 |23501212038|

接下来,把第三行加上第二行的 6 倍,可得 |23501212005|

于是原式化为了一个三角行列式。对角线乘积即为答案 5

这个方法类似高斯消元的过程。因此就把它叫做高斯消元吧。

可以看出,这个方法的时间复杂度是 O(n3) 的,完全可以接受。

带模数行列式计算

如果带模数怎么算行列式的值呢?

有一种方法叫做辗转相减法,可以完美的解决这个问题。

比如有行列式 |3241|,首先先用第二行的第一个数除以第一行第一个数,得到 1。(这里是下取整)。

然后用第二行减去第一行 ×1,得到 |3211|

容易证明第二行第一个数在操作完之后一定小于第一行第一个数。因此交换 1,2 行,得到 |1132|

重复上述操作,直到第一行为 0。得到这样的行列式:|0511|

最后再把一、二行交换即可得到下三角行列式:

|1105|

答案即为 5

由于在辗转相减的过程中可以取模,所以这个问题就被完美解决了。

分析一下复杂度。易证辗转相减的复杂度与欧几里得算法类似,为 O(logn) 级别。如果记交换两行复杂度为 O(n),那么总复杂度就为 O(n2(logn+n))

注意:两行交换时千万别忘变号!!!

代码

#include <algorithm>
#include <cstdio>
#define int long long

using namespace std;

const int N = 610;
int n, p, w[N][N], f;
void Swap(int &a, int &b) {
	for (int i = 1; i <= n; i ++ )
		swap(w[a][i], w[b][i]);
	f ^= 1; // 变号
}
int gauss() {
	for (int i = 1; i <= n; i ++ )
		for (int j = i + 1; j <= n; j ++ ) {
			while (w[i][i]) {
				int K = (int)w[j][i] / w[i][i];
				for (int k = i; k <= n; k ++ )
					((w[j][k] -= K * w[i][k] % p) += p) %= p;
				Swap(i, j);
			} Swap(i, j);
		}
	int ans = 1;
	for (int i = 1; i <= n; i ++ )
		(ans *= w[i][i]) %= p;
	return (f ? (-ans + p) % p : (ans + p) % p);
}

signed main() {
	scanf("%lld%lld", &n, &p);
	for (int i = 1; i <= n; i ++ )
		for (int j = 1; j <= n; j ++ )
			scanf("%lld", &w[i][j]);
	return 0 & printf("%lld\n", gauss());;
}

本文公式很多,可能有笔误。希望大家可以指出。

posted @   Link-Cut-Y  阅读(28)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 【.NET】调用本地 Deepseek 模型
· CSnakes vs Python.NET:高效嵌入与灵活互通的跨语言方案对比
· DeepSeek “源神”启动!「GitHub 热点速览」
· 我与微信审核的“相爱相杀”看个人小程序副业
· Plotly.NET 一个为 .NET 打造的强大开源交互式图表库
点击右上角即可分享
微信分享提示