言之有理——一个OIer兼训诂学爱好者的行列式观

· · 算法·理论

前前言——了不起!一开口便是大实话!

对于一行数与列数都为 n 的矩阵:

\left[ {\begin{array}{c} \begin{matrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right]

记其为 A_n

对于一长度为 n 的排列为 j_1 j_2 \cdots j_n,记其逆序数为 \tau (j_1 j_2 \cdots j_n),所有长度为 n 的排列构成的集合为 S_n

数学家们决定将矩阵 A_n 的“行列式”(为什么这个概念没有超链接而只用了一对单薄无力的引号呢?因为我坏!)记为 \det A_n,又记为:

\left| {\begin{array}{c} \begin{matrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right|

其计算法则是:

\det A_n = \left| {\begin{array}{c} \begin{matrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right| = \sum_{(j_1 j_2 \cdots j_n) \in S_n} (-1) ^ {\tau (j_1 j_2 \cdots j_n)} a_{1,j_1} a_{2,j_2} \cdots a_{n,j_n}

其目的是折磨你。如果你有幸学了线性代数,你会算这个算到吐。谁也不知道这东西可以干什么。

前言——不可能!绝对不可能!

我刚才骗了你。我说谁都不知道行列式可以干什么,其实是因为我自己不知道行列式可以干什么。

(噔噔噔噔噔噔)(新三权谋音)

正如某位 OIer 兼训诂学爱好者所说:

不管是为了什么目的,数学家等科学家们在使用概念时肯定是打算要办什么实事,不管这件事在一般人看来实在不实在,在他们看来肯定是有用的。

——OTTF《有的放矢——一个OIer兼训诂学爱好者的线性代数观》

矩阵的行列式运算也必定有其目的。我所忧虑的是,我目前不确切地知道它有什么目的。

我知道为什么英文中意为“决定性因素”的“determinant”一词要被翻译成“行列式”吗?不知道。我知道为什么“行列式”在有些话中指它的运算结果吗?不知道。我知道为什么明明已经有了用中括号包裹数字方阵表达矩阵的记法,却又有了用竖线包裹数字方阵表达“行列式”,甚至不惜与绝对值撞车吗?不知道。我知道逆序数为什么要在这里出现吗?不知道。我知道这一坨大求和为什么要在这里被当作一个运算吗?不知道。我什么也不知道。

我唯一知道的是:行列式这一运算不可能没有其确切目的。也就是说,我总有一天能解释这坨东西为什么要这么写:

\det A_n = \left| {\begin{array}{c} \begin{matrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right| = \sum_{(j_1 j_2 \cdots j_n) \in S_n} (-1) ^ {\tau (j_1 j_2 \cdots j_n)} a_{1,j_1} a_{2,j_2} \cdots a_{n,j_n}

刚好现在卑劣的笔者考完了期末,而尊敬的读者闲得发慌,我诚邀您与我共同寻找行列式这一 恶意(这个词原本是一个打字错误,我决定保留它)运算的目的所在。

缘起——不要愤怒,愤怒会降低你的智慧

好了,尊敬的读者。无论您是因为行列式臃肿的表达式生气,还是因为我卑劣的欺骗行为恼火,都请平静下来。让我们一同寻找行列式这一运算出现的原因。

审查行列式的定义:

\det A_n = \left| {\begin{array}{c} \begin{matrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right| = \sum_{(j_1 j_2 \cdots j_n) \in S_n} (-1) ^ {\tau (j_1 j_2 \cdots j_n)} a_{1,j_1} a_{2,j_2} \cdots a_{n,j_n}

它的求和逻辑可以被人话表达成:

对于有 n 个数的排列,遍历所有这样的排列共计 n! 个。在遍历到每一个排列时,对于排列中的第 i 个数 j_i,取出矩阵中第 i 行第 j_i 列的这个数,把这些数全都乘起来,再乘上“神奇因子”。当这个排列的逆序数为奇数时,“神奇因子”为 -1,反之则为 1。把所有乘起来的结果加起来,得到行列式。

容易发现,遍历排列并取数的操作,实际上是遍历矩阵中所有这样的 n 元组:没有数在同一行,没有数在同一列。把它们遍历完并且按照某种方式求和,这看起来确实有点用。可以联想到,它能代表矩阵的某种特性。

那么,疑问就挂在那个“神奇因子”上了。而又容易想到,根据被求和的一项的某些性质来决定它前面的系数是 -1 还是 1 也很有用,比如二项式反演就用到了这种操作。我曾写了一篇关于二项式反演的博文,可惜不符合洛谷推荐标准,我已急哭。

最终,我们需要解决的疑难是:为什么“神奇因子”跟排列的逆序数有关系?只要解答了这个问题,我们就能很好地理解行列式,也能知道它可以干什么。

求索——分子一个行列式,分母一个行列式。鹿走迁入方橙市,大家都爱行列式。

我干枯地对着电脑屏幕,怎么想也想不出来行列式里的这个逆序数有什么作用。于是我决定直接查一查行列式的作用。

最终我发现了克莱姆法则,说是能用行列式解方程。这个功能实在是太强大了,我们一起来品鉴一下。

对于有 n 个方程的 n1 次方程组:

\begin{cases} a_{1,1} x_1 &+& a_{1,2} x_2 &+& \dots & a_{1,n} x_n &=& b_1 \\ a_{2,1} x_1 &+& a_{2,2} x_2 &+& \dots & a_{2,n} x_n &=& b_2 \\ \vdots & & \vdots & & & \vdots & & \vdots \\ a_{n,1} x_1 &+& a_{n,2} x_2 &+& \dots & a_{n,n} x_n &=& b_n \end{cases}

定义它的“系数矩阵”为:

\left[ {\begin{array}{c} \begin{matrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right]

记为 A。克莱姆法则首先告诉我们,如果 det A 不等于零,那么方程组有唯一解。

然后,定义 A_j,其中 j = 1,2,\dots,n,它是在 A 基础上稍作修改得到的另一个矩阵。具体操作是:把 A 的第 j 列中的所有数粗暴地换成所在行的常数项。

比如,A_1就是:

\left[ {\begin{array}{c} \begin{matrix} b_1 & a_{1,2} & \dots & a_{1,n} \\ b_2 & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ b_n & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right]

这很容易理解。常数项太孤单了,是得让它们参加一点运算。我没有查到 A_j 这种矩阵的中文名字,但我觉得我可以把这种矩阵叫做“系数-常数矩阵”。

克莱姆法则还告诉我们这条重磅消息:

x_j = \frac {\det A_j} {\det A}

关于方程组在 \det A = 0 时的有解性,我们暂且不去论证。我们关心的是 \displaystyle x_j = \frac {\det A_j} {\det A} 这条关于解方程的信息,它让我们想到一位故人。

追寻——故人陆续凋零,好似风中落叶

你会高斯消元吗?如果你说你不会,那么其实你会,只是你不知道你会,因为高斯消元其实就是简单的代入消元法和加减消元法。我们高端 OIer 使用的高斯-约旦消元法则更是简单,简单到有煎蛋那么简单。我将带你温习高斯消元的知识,顺便提一些我曾经略过不提的矩阵小知识,这将有助于我们对克莱姆法则的证明,至少我猜是这样。

类似我们刚才的行为,对于方程组:

\begin{cases} a_{1,1} x_1 &+& a_{1,2} x_2 &+& \dots & a_{1,n} x_n &=& b_1 \\ a_{2,1} x_1 &+& a_{2,2} x_2 &+& \dots & a_{2,n} x_n &=& b_2 \\ \vdots & & \vdots & & & \vdots & & \vdots \\ a_{n,1} x_1 &+& a_{n,2} x_2 &+& \dots & a_{n,n} x_n &=& b_n \end{cases}

我们提取出矩阵:

\left[ {\begin{array}{c|c} \begin{matrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} & \begin{matrix} b_1 \\ b_2 \\ \vdots \\ b_n \\ \end{matrix} \end{array}} \right]

比起之前的“系数矩阵”,这个矩阵还多了竖线右边的那些常数项部分。我们把这个矩阵叫做“增广矩阵”,因为它比“系数矩阵”被“增广”——或者说“添加”——了一列,这一列又被叫做“常数列”。

显然增广矩阵能完全提供一个方程组的信息,今后我们一般用它来表示方程组。可想而知,如果我们最终解出了一个方程组,那么我们最终肯定得到的是这样的增广矩阵:

\left[ {\begin{array}{c|c} \begin{matrix} 1 & 0 & \dots & 0 \\ 0 & 1 & \dots & 0 \\ \vdots & \vdots & & \vdots \\ 0 & 0 & \dots & 1 \end{matrix} & \begin{matrix} ans_1 \\ ans_2 \\ \vdots \\ ans_n \\ \end{matrix} \end{array}} \right]

即:在竖线左边,只有从左上到右下的这条对角线上是 1,其他位置都是 0;在竖线右边,第 i 行的数 ans_i 代表第 i 个未知数 x_i 的值,也就是 ans_i = x_i

我要补充的第一个知识点是,竖线左边的这个矩阵:

\left[ {\begin{array}{c} \begin{matrix} 1 & 0 & \dots & 0 \\ 0 & 1 & \dots & 0 \\ \vdots & \vdots & & \vdots \\ 0 & 0 & \dots & 1 \end{matrix} \end{array}} \right]

实在是太特殊了。它只有对角线上是 1,其他位置都是 0,而且行数等于列数。人们把这种矩阵定义为“单位矩阵”,并通常把这种矩阵记作 I_n,其中 n 是它的行数,当然也是它的列数。它的特殊性质在于,对于一个矩阵 A,如果它能放在 I_n 的左边与之相乘,那么 A \times I_n = A;类似的,如果 A 能在 I_n 的右边与之相乘,那么也有 I_n \times A = A。单位矩阵能在矩阵乘法中起到类似 1 的作用,或者说,“单位元”的作用。

回到高斯消元。结合我们在初中解一元一次方程和二元一次方程组的经验,我们一般会在见到上面那种方程组之前见到下面这种方程组,然后进行“化系数为 1”的操作:

\left[ {\begin{array}{c|c} \begin{matrix} left_1 & 0 & \dots & 0 \\ 0 & left_2 & \dots & 0 \\ \vdots & \vdots & & \vdots \\ 0 & 0 & \dots & left_n \end{matrix} & \begin{matrix} right_1 \\ right_2 \\ \vdots \\ right_n \\ \end{matrix} \end{array}} \right]

不难理解,把上面两个增广矩阵放在一起看,我们可以轻松的拿 right_i 除以 left_i 得到 ans_i,即对于第 i 行,有 \displaystyle ans_i = \frac {right_i} {left_i}

我要补充的第二个知识点是,竖线左边的这种矩阵:

\left[ {\begin{array}{c} \begin{matrix} left_1 & 0 & \dots & 0 \\ 0 & left_2 & \dots & 0 \\ \vdots & \vdots & & \vdots \\ 0 & 0 & \dots & left_n \end{matrix} \end{array}} \right]

依然被认为是特殊的,它的行数和列数依然相等,并且只有对角线上有不是 0 的值,虽然它们不一定是 1。我们管它叫做“对角线矩阵”,它可以被记作 diag (left_1, left_2, \dots, left_n)

现在我们要做的是,把这种增广矩阵:

\left[ {\begin{array}{c|c} \begin{matrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} & \begin{matrix} b_1 \\ b_2 \\ \vdots \\ b_n \\ \end{matrix} \end{array}} \right]

变成这种增广矩阵:

\left[ {\begin{array}{c|c} \begin{matrix} left_1 & 0 & \dots & 0 \\ 0 & left_2 & \dots & 0 \\ \vdots & \vdots & & \vdots \\ 0 & 0 & \dots & left_n \end{matrix} & \begin{matrix} right_1 \\ right_2 \\ \vdots \\ right_n \\ \end{matrix} \end{array}} \right]

也就是说,我们需要找到某种一般化的操作,使得对于竖线左边的第 i 行,只有第 i 个数不是 0

追忆一下我们在初中学到的解二元一次方程组内容,我们手头没什么让方程组自己现出对角线矩阵的武器,只能让它们自取灭亡——这就叫做消元。具体来说,我们先挑出喜欢的一行,比如第 1 行吧:

\left[ {\begin{array}{c|c} \begin{matrix} \textcolor{red}{a_{1,1}} & \textcolor{red}{a_{1,2}} & \textcolor{red}{\dots} & \textcolor{red}{a_{1,n}} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} & \begin{matrix} \textcolor{red}{b_1} \\ b_2 \\ \vdots \\ b_n \\ \end{matrix} \end{array}} \right]

由于我们的消元刚刚开始,现在我们打算灭掉矩阵中其他行的第 1 列的数。如果只想道要灭掉 a_{2,1}, a_{3,1}, \dots, a_{n,1} 这些数,那么只需要直接把它们都设成 0 就行了。可是别忘了,后面还有好多数呢!我们需要保证方程的解不变,显然,方程都是等式,一个等式减去一个等式,它们的性质不会发生改变,如果后者全体扩了几倍也是这样。所以,我们让其他每一行都减去第 1 行扩上几倍的数值,使得第 1 行变成 0

\left[ {\begin{array}{c|c} \begin{matrix} \textcolor{red}{a_{1,1}} & \textcolor{red}{a_{1,2}} & \textcolor{red}{\dots} & \textcolor{red}{a_{1,n}} \\ a_{2,1} - a_{1,1} \times \frac {a_{2,1}} {a_{1,1}} & a_{2,2} - a_{1,2} \times \frac {a_{2,1}} {a_{1,1}} & \dots & a_{2,n} - a_{1,n} \times \frac {a_{2,1}} {a_{1,1}} \\ \vdots & \vdots & & \vdots \\ a_{n,1} - a_{1,1} \times \frac {a_{n,1}} {a_{1,1}} & a_{n,2} - a_{1,2} \times \frac {a_{n,1}} {a_{1,1}} & \dots & a_{n,n} - a_{1,n} \times \frac {a_{n,1}} {a_{1,1}} \end{matrix} & \begin{matrix} \textcolor{red}{a_{1,n+1}} \\ a_{2,n+1} - a_{1,n+1} \times \frac {a_{2,1}} {a_{1,1}} \\ \vdots \\ a_{n,n+1} - a_{1,n+1} \times \frac {a_{n,1}} {a_{1,1}} \\ \end{matrix} \end{array}} \right]

啊哈!规律在于,对于第 i 行的第 j 个数,它要减去 a_{1,j} \times \frac {a_{i,1}} {a_{1,1}}。当然,这建立在我已经将每个 b_i 偷换成了 a_{i,{n+1}},并且我们想要消掉每一行的第 1 个数的基础上。

把我们得到的新增广矩阵整理一下,把得到 0 的位置写成 0,而用 a_{i,j} 替代每个无法再化简的位置——显然它的含义发生了变化,我们可以得到:

\left[ {\begin{array}{c|c} \begin{matrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ 0 & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ 0 & a_{n,2} & \dots & a_{n,n} \end{matrix} & \begin{matrix} a_{1,n+1} \\ a_{2,n+1} \\ \vdots \\ a_{n,n+1} \\ \end{matrix} \end{array}} \right]

对角线矩阵可以被认为是第 i 列只有第 i 行的数不是 0 的矩阵,而我们现在走完了第一步:第 1 列只有第 1 行的数不是 0

如果我们用第 2 行尝试去消去其他行的第 2 列,会出什么差池吗?仿照刚才的行为,我们这次把第 2 行标红,并且让每个数 a_{i,j} 减去 a_{2,j} \times \frac {a_{i,2}} {a_{2,2}}

\left[ {\begin{array}{c|c} \begin{matrix} a_{1,1} - a_{2,1} \times \frac {a_{1,2}} {a_{2,2}} & a_{1,2} - a_{2,2} \times \frac {a_{1,2}} {a_{2,2}} & \dots & a_{1,n} - a_{2,n} \times \frac {a_{1,2}} {a_{2,2}} \\ \textcolor{red}{0} & \textcolor{red}{a_{2,2}} & \dots & \textcolor{red}{a_{2,n}} \\ \vdots & \vdots & & \vdots \\ 0 - a_{2,1} \times \frac {a_{n,2}} {a_{2,2}} & a_{n,2} - a_{2,2} \times \frac {a_{n,2}} {a_{2,2}} & \dots & a_{n,n} - a_{2,n} \times \frac {a_{n,2}} {a_{2,2}} \end{matrix} & \begin{matrix} a_{1,n+1} - a_{2,n+1} \times \frac {a_{1,2}} {a_{2,2}} \\ \textcolor{red}{a_{2,n+1}} \\ \vdots \\ a_{n,n+1} - a_{2,n+1} \times \frac {a_{n,2}} {a_{2,2}} \\ \end{matrix} \end{array}} \right]

对于第 1 列,由于 a_{2,1} 已经变成了 0,所以它们其实都是 0 - 0,还是 0。对于第 2 列,它们也都变成了 0。对于其他列,它们只是勤勤恳恳地运算。啊哈!完全没有问题!

所以,我们要做的就是,重复 n 次:对于第 i 次,每次找出喜欢的一行,比如第 line 行,对于不在第 line 行的数 a_{j,k},它需要变成 a_{j,k} - a_{line,k} \times \frac {a_{j,i}} {a_{line,i}},这将保证我们能拿着 a_{line,i} 消掉其他行的第 i 个数。

在 OI 领域,由于计算精度等原因,这个“喜欢的一行”一般被定为“第 i 个数的绝对值最大的一行”。而显然,如果在计算中某列的所有数都是 0,那么这个方程组没有唯一解;此时如果存在非零常数项,则这个方程组无解,否则这个方程组有无数解。

我们在此使用的消元算法实则是高斯消元的扩展版本,原始的高斯消元不对曾经被标红的行进行处理,最终竖线左边只得到一个“上三角形矩阵”(读者可以自行理解它的含义),当然它可以用代入消元法来继续解,只是有点麻烦。我们这里的算法被称为“高斯-约旦消元”,把之前标红过的行继续消元,顺手的事儿。不管是否扩展,这种消元的时间复杂度都是 O (n^3) 的。

更多实现细节参阅以下代码:

#include <algorithm>
#include <cmath>

using namespace std;

const int N = 55;
const long double eps = 1e-6;

namespace Gauss_Eli {
    /*
    require:
        constant : N
        funcction : abs swap
        head file : algorithm cmath
    */

    void solve (long double arr[N][N], long double res[N], int n) {
        int main_line = 1;
        for (int i = 1; i <= n; i++) {
            int maxn_line = main_line;
            for (int j = main_line + 1; j <= n; j++) {
                if (abs (arr[maxn_line][i]) < abs (arr[j][i])) {
                    maxn_line = j;
                }
            }
            if (abs (arr[maxn_line][i]) < eps) {
                continue;
            }

            if (main_line != maxn_line) {
                swap (arr[main_line], arr[maxn_line]);
            }

            for (int j = 1; j <= n; j++) {
                if (j == main_line) {
                    continue;
                }
                long double t = arr[j][i] / arr[main_line][i];
                for (int k = main_line; k <= n + 1; k++) {
                    arr[j][k] -= arr[main_line][k] * t;
                }
            }
            main_line++;
        }

        if (main_line <= n) {
            while (main_line <= n) {
                if (abs (arr[main_line++][n + 1]) > eps) {
                    res[0] = -1;
                    return;
                }
            }
            res[0] = 1;
            return;
        }

        for (int i = 1; i <= n; i++) {
            res[i] = arr[i][n + 1] / arr[i][i];
        }
    }
}

基于该高斯-约旦消元算法编写的代码已经通过洛谷题目P2455 [SDOI2006] 线性方程组,详见记录R286028391。

回忆一下我之前提到的“单位矩阵”I_n

\left[ {\begin{array}{c} \begin{matrix} 1 & 0 & \dots & 0 \\ 0 & 1 & \dots & 0 \\ \vdots & \vdots & & \vdots \\ 0 & 0 & \dots & 1 \end{matrix} \end{array}} \right]

我曾经说过,单位矩阵很像 1。那么既然矩阵乘法中存在 1,是不是也存在 \frac {1} {x} 呢?或者说……倒数?“倒矩阵”?

答案是:是!不过我们叫它“逆矩阵”。具体来说,对于 n 阶矩阵 A——我刚发现“n 阶矩阵”这个词可以表示“行数和列数都为 n 的矩阵”——它的逆矩阵也是一个 n 阶矩阵,记为 A^{-1},其满足 A \times A^{-1} = I_n

如果你发现我在讲解另一个大知识点时没有更换小标题,会不会很恐惧?哈哈哈!事实上我们可以用高斯-约旦消元来解决这个问题。类似于矩阵 Aa_{i,j},我们用 a'_{i,j}表示 A^{-1} 的第 i 行第 j 列。那么我们有:

\left[ {\begin{array}{c} \begin{matrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right] \times \left[ {\begin{array}{c} \begin{matrix} a'_{1,1} & a'_{1,2} & \dots & a'_{1,n} \\ a'_{2,1} & a'_{2,2} & \dots & a'_{2,n} \\ \vdots & \vdots & & \vdots \\ a'_{n,1} & a'_{n,2} & \dots & a'_{n,n} \end{matrix} \end{array}} \right] = \left[ {\begin{array}{c} \begin{matrix} 1 & 0 & \dots & 0 \\ 0 & 1 & \dots & 0 \\ \vdots & \vdots & & \vdots \\ 0 & 0 & \dots & 1 \end{matrix} \end{array}} \right]

而当我们想要解如下的方程组:

\begin{cases} a_{1,1} x_1 &+& a_{1,2} x_2 &+& \dots & a_{1,n} x_n &=& a_{1,n+1} \\ a_{2,1} x_1 &+& a_{2,2} x_2 &+& \dots & a_{2,n} x_n &=& a_{2,n+1} \\ \vdots & & \vdots & & & \vdots & & \vdots \\ a_{n,1} x_1 &+& a_{n,2} x_2 &+& \dots & a_{n,n} x_n &=& a_{n,n+1} \end{cases}

我们其实能用如下的矩阵乘法代表它:

\left[ {\begin{array}{c} \begin{matrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right] \times \left[ {\begin{array}{c} \begin{matrix} x_1 \\ x_2 \\ \vdots \\ x_n \end{matrix} \end{array}} \right] = \left[ {\begin{array}{c} \begin{matrix} a_{1,n+1} \\ a_{2,n+1} \\ \vdots \\ a_{n,n+1} \end{matrix} \end{array}} \right]

发现了吗?对于一个 n 阶矩阵 A,以及一个行数为 n 列数为 1 的矩阵 B,解方程这个行为其实是在寻找另一个行数为 n 列数为 1 的矩阵 X,使得 A \times X = B

而对于矩阵求逆这个操作:

\left[ {\begin{array}{c} \begin{matrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right] \times \left[ {\begin{array}{c} \begin{matrix} a'_{1,1} & a'_{1,2} & \dots & a'_{1,n} \\ a'_{2,1} & a'_{2,2} & \dots & a'_{2,n} \\ \vdots & \vdots & & \vdots \\ a'_{n,1} & a'_{n,2} & \dots & a'_{n,n} \end{matrix} \end{array}} \right] = \left[ {\begin{array}{c} \begin{matrix} 1 & 0 & \dots & 0 \\ 0 & 1 & \dots & 0 \\ \vdots & \vdots & & \vdots \\ 0 & 0 & \dots & 1 \end{matrix} \end{array}} \right]

依据矩阵乘法的性质,我们有足够的信心把它拆解成若干条这样的操作:

\left[ {\begin{array}{c} \begin{matrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right] \times \left[ {\begin{array}{c} \begin{matrix} a'_{1,j} \\ a'_{2,j} \\ \vdots \\ a'_{n,j} \end{matrix} \end{array}} \right] = \left[ {\begin{array}{c} \begin{matrix} ans_{1,j} \\ ans_{2,j} \\ \vdots \\ ans_{n,j} \end{matrix} \end{array}} \right]

其中乘号左边的方形矩阵我们是有的,等号右边的长条矩阵是从单位矩阵中抽取的,那么剩下来的那个矩阵就是可以用高斯-约旦消元算出来的。我们当然可以重复这样做 n 次,从而得到整个 A^{-1}。不过我们也可以直接把 AI_n 拼起来:

\left[ {\begin{array}{c|c} \begin{matrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} & \begin{matrix} 1 & 0 & \dots & 0 \\ 0 & 1 & \dots & 0 \\ \vdots & \vdots & & \vdots \\ 0 & 0 & \dots & 1 \end{matrix} \end{array}} \right]

然后直接拿着它的左半边做一次消元,最终得到:

\left[ {\begin{array}{c|c} \begin{matrix} 1 & 0 & \dots & 0 \\ 0 & 1 & \dots & 0 \\ \vdots & \vdots & & \vdots \\ 0 & 0 & \dots & 1 \end{matrix} & \begin{matrix} a'_{1,1} & a'_{1,2} & \dots & a'_{1,n} \\ a'_{2,1} & a'_{2,2} & \dots & a'_{2,n} \\ \vdots & \vdots & & \vdots \\ a'_{n,1} & a'_{n,2} & \dots & a'_{n,n} \end{matrix} \end{array}} \right]

我的记法已经暗示了,竖线右边就是 A^{-1}

沉思——这三大初等变换往这一站,这大半个线性代数就在我们的脚底下了!

喜报:之前我一直不明白行列式的意义,梦到哪里写哪里,但昨天晚上我突然在睡梦前悟出来了,我们今后的旅程将更为顺畅。今天将是伟大的一天!

整理我们拥有的关于行列式的信息。首先我们知道它的定义:

\det A_n = \left| {\begin{array}{c} \begin{matrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right| = \sum_{(j_1 j_2 \cdots j_n) \in S_n} (-1) ^ {\tau (j_1 j_2 \cdots j_n)} a_{1,j_1} a_{2,j_2} \cdots a_{n,j_n}

令人费解之处在于逆序数的神秘出现,不过我已经把它悟出来了,待会儿我就说明。

其次我们知道它的一大作用,对于方程组:

\begin{cases} a_{1,1} x_1 &+& a_{1,2} x_2 &+& \dots & a_{1,n} x_n &=& b_1 \\ a_{2,1} x_1 &+& a_{2,2} x_2 &+& \dots & a_{2,n} x_n &=& b_2 \\ \vdots & & \vdots & & & \vdots & & \vdots \\ a_{n,1} x_1 &+& a_{n,2} x_2 &+& \dots & a_{n,n} x_n &=& b_n \end{cases}

如果它无唯一解,也就是无解或者有无数解,那么:

\det A = 0

如果它有唯一解,那么:

x_j = \frac {\det A_j} {\det A}

这被称为克莱姆法则。如果我们能把克莱姆法则证明出来,那么我们就能接受:行列式是 n 阶矩阵内部的一种性质,其与线性方程组的求解密切相关,这是其独到的关于逆序数的计算决定的。

而为了证明克莱姆法则,我们首先需要再了解更多我之前忽略不提的线性代数概念。跟好我的节奏!

追忆我们用高斯-约旦消元解方程组的过程,可以发现,我们通篇的核心操作是:挑选一行 line,对于不在这行的所有 a_{j,k},把它变成 a_{j,k} - a_{line,k} \times \frac {a_{j,i}} {a_{line,i}}。也就是:拿某一行全体乘上几倍的结果,直接加到另一些行上面——注意减一个数等于加这个数的 -1 倍。

这种消元能用来解方程组,其本质在于把不好解的一般方程组转化为好解的、增广矩阵竖线左侧为对角线矩阵的特殊方程组。很重要的是,在这种转化过程中,方程组的解不会改变,我们知道这是因为等式的性质。

欸!系数矩阵的行列式和“系数-参数矩阵”的行列式也被用来解方程,如果在上述的操作中,方程的解不改变,那是不是意味着这些行列式也不会改变?具体地,我们思考,以下式子是成立的吗:

\left| {\begin{array}{c} \begin{matrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right| = \left| {\begin{array}{c} \begin{matrix} a_{1,1} + k \times a_{2,1} & a_{1,2} + k \times a_{2,2} & \dots & a_{1,n} + k \times a_{2,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right|

解决这个问题的要点在于盯着等号的右边,以及行列式的定义:

\det A_n = \left| {\begin{array}{c} \begin{matrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right| = \sum_{(j_1 j_2 \cdots j_n) \in S_n} (-1) ^ {\tau (j_1 j_2 \cdots j_n)} a_{1,j_1} a_{2,j_2} \cdots a_{n,j_n}

哦!我们有头绪了!我们知道,行列式的计算会在每一行都选且仅选一个数,并且使得它们两两不同列,然后把它们乘起来,再乘上和逆序数相关的“神奇因子”,这个得到的乘积中必定有一项来源于行列式的第 1 行——当然,每一行都是如此,只是我们关心这一行——而这些乘积会被加起来得到答案。那么,很容易想到:

\begin{align*} & \left| {\begin{array}{c} \begin{matrix} a_{1,1} + k \times a_{2,1} & a_{1,2} + k \times a_{2,2} & \dots & a_{1,n} + k \times a_{2,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right| \\ = & \sum_{(j_1 j_2 \cdots j_n) \in S_n} (-1) ^ {\tau (j_1 j_2 \cdots j_n)} (a_{1,j_1} + k \times a_{2,j_1}) a_{2,j_2} \cdots a_{n,j_n} \\ = & \sum_{(j_1 j_2 \cdots j_n) \in S_n} (-1) ^ {\tau (j_1 j_2 \cdots j_n)} a_{1,j_1} a_{2,j_2} \cdots a_{n,j_n} + \sum_{(j_1 j_2 \cdots j_n) \in S_n} (-1) ^ {\tau (j_1 j_2 \cdots j_n)} (k \times a_{2,j_1}) a_{2,j_2} \cdots a_{n,j_n} \\ = & \left| {\begin{array}{c} \begin{matrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right| + \left| {\begin{array}{c} \begin{matrix} k \times a_{2,1} & k \times a_{2,2} & \dots & k \times a_{2,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right| \end{align*}

也就是说,运用简单的乘法分配律,我们就得到了:

\left| {\begin{array}{c} \begin{matrix} a_{1,1} + k \times a_{2,1} & a_{1,2} + k \times a_{2,2} & \dots & a_{1,n} + k \times a_{2,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right| = \left| {\begin{array}{c} \begin{matrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right| + \left| {\begin{array}{c} \begin{matrix} k \times a_{2,1} & k \times a_{2,2} & \dots & k \times a_{2,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right|

那么,我们要证明的也就是:

\left| {\begin{array}{c} \begin{matrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right| = \left| {\begin{array}{c} \begin{matrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right| + \left| {\begin{array}{c} \begin{matrix} k \times a_{2,1} & k \times a_{2,2} & \dots & k \times a_{2,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right|

即:

\left| {\begin{array}{c} \begin{matrix} k \times a_{2,1} & k \times a_{2,2} & \dots & k \times a_{2,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right| = 0

证明它的方法同样是盯着它并且参考定义。我们能发现,对于每一个被用来求和的项,一定能找到另一项,使得它们选择的位于第 1 行和第 2 行的数的列数刚好相反,而其他数则完全相同。这两个项的数值将完全相同,但符号则会相反,因为它们的逆序数肯定差了 1。具体来说,在用这个式子计算行列式时:

\sum_{(j_1 j_2 \cdots j_n) \in S_n} (-1) ^ {\tau (j_1 j_2 \cdots j_n)} (k \times a_{2,j_1}) a_{2,j_2} \cdots a_{n,j_n}

我们每取出一项:

(-1) ^ {\tau (j_1 j_2 \cdots j_n)} (k \times a_{2,j_1}) a_{2,j_2} \cdots a_{n,j_n}

就也能取出一项:

(-1) ^ {\tau (j_2 j_1 \cdots j_n)} (k \times a_{2,j_2}) a_{2,j_1} \cdots a_{n,j_n}

上下两项对应的排列的第 1 个数和第 2 个数互换,其他数相同。

通过乘法交换律,我们有:

(k \times a_{2,j_1}) a_{2,j_2} \cdots a_{n,j_n} = (k \times a_{2,j_2}) a_{2,j_1} \cdots a_{n,j_n}

而由于排列 j_1 j_2 \cdots j_nj_2 j_1 \cdots j_n 的差别在于交换了一对数,这必定造成逆序数的值变动 1,即加 1 或者减 1。无论是哪种变动,这都使 -1 的两者的逆序数次方互为相反数,即:

(-1) ^ {\tau (j_1 j_2 \cdots j_n)} = -(-1) ^ {\tau (j_2 j_1 \cdots j_n)}

因此:

(-1) ^ {\tau (j_1 j_2 \cdots j_n)} (k \times a_{2,j_1}) a_{2,j_2} \cdots a_{n,j_n} = -(-1) ^ {\tau (j_2 j_1 \cdots j_n)} (k \times a_{2,j_2}) a_{2,j_1} \cdots a_{n,j_n}

一个求和,每挑出一项,求和中有且仅有对应的另一项,使它们互为相反数,显然,这个求和的值为 0

所以,我们证明了:

\left| {\begin{array}{c} \begin{matrix} k \times a_{2,1} & k \times a_{2,2} & \dots & k \times a_{2,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right| = 0

于是我们证明了:

\left| {\begin{array}{c} \begin{matrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right| = \left| {\begin{array}{c} \begin{matrix} a_{1,1} + k \times a_{2,1} & a_{1,2} + k \times a_{2,2} & \dots & a_{1,n} + k \times a_{2,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right|

更通用地来说,我们证明了以下操作不会改变一个 n 阶矩阵的行列式:让其中的第 i 行的每个数增加其所在列的第 j 行的数的 k 倍。可以看到,这种操作不仅和解方程相关,或许还和行列式的基本性质相关,它是线性代数领域的一种重要矩阵操作。因此,人们特意为它其起了一个名字——倍加,同时它被认为是一种“初等变换”。

我好像曾经说过,矩阵乘法可以被看作是往矩阵上施加的一种“变换”——你看,“变换”,“初等变换”,很显然初等变换可以被矩阵乘法表示。具体来说,对于 n 阶矩阵 A,我们需要“倍加矩阵”T_{i,j}(k),使得 T_{i,j}(k) \times A 得到对矩阵 A 施加“其中的第 i 行的每个数增加其所在列的第 j 行的数的 k 倍”这一基本操作的结果。经过一点点思考,我们可以知道,T_{i,j}(k) 与单位矩阵相差无几,区别在于它的第 i 行第 j 列为 k,即 {T_{i,j}(k)}_{i,j} = k

还有另外两种初等变换:一种是“倍乘”,其“倍乘矩阵” D_i(k) 使得 D_i(k) \times A 的第 i 行的所有数是 A 的第 i 行的相应数的 k 倍,也就是把某一行整体扩倍;另一种是“互换”,其“互换矩阵” P_{i,j} 使得 P_{i,j} \times A 的第 i 行和第 j 行相较 A 互换,也就是互换两行。而 D_i(k)P_{i,j} 也都可以被视为由单位矩阵修改而来,其中 D_i(k) 的修改是令 {D_i(k)}_{i,i} = k,而 P_{i,j} 的修改则是令 {P_{i,j}}_{i,i} = {P_{i,j}}_{j,j} = 0{P_{i,j}}_{i,j} = {P_{i,j}}_{j,i} = 1。当然,如果你把所有“行”字和所有“列”字对换,你可以得到新一批初等变换,我刚才提到的初等变换被称为“初等行变换”,对换那两个字后得到的初等变换则被称为“初等列变换”。

之前我们已经证明过了,倍加不改变 n 阶矩阵的行列式,这可以被记为 \det (T_{i,j}(k) \times A) = \det A。容易发现,倍乘让行列式计算中的求和的每一项都变为原来的 k 倍,于是它使行列式也变为原来的 k 倍,即 \det (D_i(k) \times A) = k \times \det A;而互换则可以被视为改变了求和中每一种数的选法所对应的逆序数的奇偶性,即改变了“神奇因子”是 1 还是 -1,这将让行列式的符号改变,即 \det (P_{i,j} \times A) = - \det A

想象 T_{i,j}(k) 的数如何处于它之中:从左上到右下的对角线上的数都是 1,同时有单独的 {T_{i,j}(k)}_{i,j} = k。如果计算 \det (T_{i,j}(k)),只有取的数全都是那条对角线上的数时才能乘出 1,否则乘积一定是 0,因此 \det (T_{i,j}(k)) = 1。更简单地,显然 \det (D_i(k)) = k,它甚至是个简单的对角线矩阵;而 \det (P_{i,j}) = -1,因为当且仅当全部取 1 时能乘出非零项,而这时逆序数是 1,“神奇因子”是 -1

不难发现:

\begin{align*} \det (T_{i,j}(k) \times A) & = & 1 \times \det A & = & \det (T_{i,j}(k)) \times \det A \\ \det (D_i(k) \times A) & = & k \times \det A & = & \det (D_i(k)) \times \det A \\ \det (P_{i,j} \times A) & = & -1 \times \det A & = & \det (P_{i,j}) \times \det A \end{align*}

这启示我们,或许对于任何另一个矩阵 B,都有 \det (B \times A) = \det (B) \times \det (A)?可想而知,这会很有用,所以如何证明它呢?

追忆高斯-约旦消元的操作,对于竖线左边的系数矩阵,我们总能把它变成单位矩阵——不!有时方程会无解!这时左边的矩阵就无法变成单位矩阵,而是会出现一行全是 0!这表示 n 阶矩阵可以被分成两部分:可以被消元成单位矩阵的,和不可以的。又因为消元和矩阵求逆的密切关系,这种分类等同于:有逆矩阵的和没有逆矩阵的。我们把前者叫做“非奇异矩阵”,后者叫做“奇异矩阵”。显然,高斯-约旦消元在得到对角线矩阵的那部分只用到了倍加这一初等行变换,而在化系数为一的那部分则只用到了倍乘——都是初等行变换。所以我们可以说:任何非奇异矩阵都可以通过初等行变换变为单位矩阵。类似地,由于奇异矩阵无法被完全消元,我们也可以说:任何奇异矩阵都无法通过初等行变换变为单位矩阵。

既然矩阵乘法是一种“变换”的操作,那么逆矩阵就可以被视为是一种“撤销”,倍加、倍乘、互换这三种初等行变换都能分别用它们自己调调数值的版本来撤销,那么,倍加矩阵、倍乘矩阵、互换矩阵也肯定有自己的逆矩阵——它们都是非奇异矩阵。因此,既然任何非奇异矩阵都可以通过初等行变换变为单位矩阵,单位矩阵也肯定能反过来,通过乘一些初等行变换对应的矩阵变为任何非奇异矩阵。也就是说,任何非奇异矩阵都可以被视为是若干初等变换对应的矩阵的积。这样,非奇异矩阵 B 就可以被认为是若干初等变换对应的矩阵的积。因此,我们可以知道,由于有了我们在上面列出的三个长式子,所以如果 AB 都是非奇异矩阵,那么肯定有 \det (B \times A) = \det (B) \times \det (A)

那如果 B 是奇异矩阵而 A 不是呢?继续追忆高斯-约旦消元的操作,我们知道,如果竖线左边是奇异矩阵,那么我们将会在化系数为一之前被迫停止,且得到的系数矩阵肯定会有一行全是 0,而显然,它的行列式等于 0。在化系数为一之前的操作都是倍加,而倍加操作不改变矩阵的行列式,这意味着:任何奇异矩阵的行列式都是 0。而如果一个奇异矩阵和一个非奇异矩阵相乘,啊,这可以被视为一个奇异矩阵经过了若干次初等行变换,最终得到的也还是一个奇异矩阵!因此,我们有 \det (B \times A) = 0 = \det (B) \times \det (A)

最后,如果 AB 都是奇异矩阵呢?哈哈,这两个魔丸!对于 A,它是奇异矩阵,把它放到消元里,得到的结果就是无解或者有无穷多种解。如果有无穷多种解,那么这时右边的常数就都是 0——这种情况肯定存在,对于所有不全是 0 的情况,显然微操常数的初始值就能把它们的最终值都变成 0。啊!对于 n 阶奇异矩阵 A,存在 n1 列的矩阵——或者说列向量——X,使得 A \times X = \boldsymbol {0},其中 \boldsymbol {0} 代表一个 n1 列的矩阵——或者说列向量——其所有数都为 0,并且 X \neq \boldsymbol {0}

既然 A \times X = \boldsymbol {0},那么 B \times (A \times X) = B \times \boldsymbol {0}。对于左边,矩阵乘法有结合律;对于右边,显然得到 \boldsymbol {0},所以:

(B \times A) \times X = B \times (A \times X) = B \times \boldsymbol {0} = \boldsymbol {0}

所以,对于 B \times A,它也能找到 X 使得 (B \times A) \times X = \boldsymbol {0},并且 X \neq \boldsymbol {0}。那么,它也是一个奇异矩阵!因此,当 AB 都是奇异矩阵,一样有 \det (B \times A) = 0 = \det (B) \times \det (A)

最终,我们证明了对于任何 n 阶矩阵 AB,无论它们是不是奇异矩阵,都一定有 \det (B \times A) = \det (B) \times \det (A)

高潮——证得好啊,证得咱家心里舒服死了!

现在开始证明克拉默法则。

\det A = 0,我们已经说过了,这代表高斯-约旦消元中竖线左边的系数矩阵是奇异矩阵,也代表方程组无唯一解。

\det A \neq 0,即这个系数矩阵不是奇异矩阵,它有逆矩阵,我们把它记为 A^{-1},对于:

\begin{align*} \frac {\det A_j} {\det A} \end{align*}

分子分母同时乘以 \det A^{-1},得到:

\begin{align*} & \frac {\det A_j} {\det A} \\ =& \frac {\det A^{-1} \times \det A_j} {\det A^{-1} \times \det A} \\ =& \frac {\det (A^{-1} \times A_j)} {\det (A^{-1} \times A)} \\ =& \frac {\det (A^{-1} \times A_j)} {\det I_n} \\ =& \frac {\det (A^{-1} \times A_j)} {1} \\ =& \det (A^{-1} \times A_j) \end{align*}

对于正在解的线性方程组,我们用矩阵乘法把它表示为:

\left[ {\begin{array}{c} \begin{matrix} a_{1,1} & a_{1,2} & \dots & a_{1,n} \\ a_{2,1} & a_{2,2} & \dots & a_{2,n} \\ \vdots & \vdots & & \vdots \\ a_{n,1} & a_{n,2} & \dots & a_{n,n} \end{matrix} \end{array}} \right] \times \left[ {\begin{array}{c} \begin{matrix} x_1 \\ x_2 \\ \vdots \\ x_n \end{matrix} \end{array}} \right] = \left[ {\begin{array}{c} \begin{matrix} a_{1,n+1} \\ a_{2,n+1} \\ \vdots \\ a_{n,n+1} \end{matrix} \end{array}} \right]

简记为:

A \times X = B

两边同时乘以 A^{-1},有:

A^{-1} \times (A \times X) = A^{-1} \times B

根据乘法结合律:

(A^{-1} \times A) \times X = A^{-1} \times B

即:

I_n \times X = A^{-1} \times B

即:

X = A^{-1} \times B

啊,A^{-1} \times B 能得到 X,或者说系数矩阵的逆矩阵与常数矩阵相乘能得到未知数矩阵。而之前我们得到的 A^{-1} \times A_j,根据 A_j 作为“系数-常数矩阵”的定义和矩阵乘法的法则,其在乘法进行到 A_j 的第 j 列时的行为是计算 A^{-1} \times B,而在进行到它的其他列时的行为则是计算 A^{-1}A 的某一列的乘积。这使我们得到:

A^{-1} \times A_j = \left[ {\begin{array}{c} \begin{matrix} 1 & 0 & \dots & 0 & x_1 & 0 & \dots & 0 & 0 \\ 0 & 1 & \dots & 0 & x_2 & 0 & \dots & 0 & 0 \\ \vdots & \vdots & & \vdots & \vdots & \vdots & & \vdots & \vdots \\ 0 & 0 & \dots & 1 & x_{j-1} & 0 & \dots & 0 & 0 \\ 0 & 0 & \dots & 0 & x_j & 0 & \dots & 0 & 0 \\ 0 & 0 & \dots & 0 & x_{j+1} & 1 & \dots & 0 & 0 \\ \vdots & \vdots & & \vdots & \vdots & \vdots & & \vdots & \vdots \\ 0 & 0 & \dots & 0 & x_{n-1} & 0 & \dots & 1 & 0 \\ 0 & 0 & \dots & 0 & x_n & 0 & \dots & 0 & 1 \\ \end{matrix} \end{array}} \right]

即,A^{-1} \times A_j 的结果大致是一个单位矩阵,只是第 j 列变成了常数矩阵 X。如果计算它的行列式,显然只有在选中从左上到右下的对角线的所有数时才能得到非零项,于是:

\det (A^{-1} \times A_j) = x_j

即,克拉默法则的线性方程组求解方法:

x_j = \frac {\det A_j} {\det A}

得到证明。

呜呼!我们是冠军!

结局——天意所至,你想不胜都难

感谢大家的一路陪伴,现在我们已经知道了行列式臃肿的计算方法的作用:它通过大乘积、大求和、以及有关逆序数奇偶性的“神奇因子”使得矩阵的行列式不被倍加操作改变,在发生倍乘操作时扩倍,在发生互换操作时改变符号——即在发生初等行变换时乘上某个数;同时它还使有一行全是 0 的矩阵的行列式是 0,而单位矩阵的行列式是 1。以上两点使得矩阵的行列式与它是不是奇异矩阵相关联,还使得“矩阵的行列式的积等于矩阵的积的行列式”这条好用的性质是正确的,这使得克拉默法则是正确的。因此,我们说:行列式可以被视为反映线性方程组解的情况——有没有唯一的、若有则是什么——的神奇数值。

参考文献——列位诸公

排名不分先后,它们都是我的翅膀。

克拉默法则(Cramer's Rule)的证明

克莱姆法则_百度百科

初等变换 - OI Wiki

深入理解 | 超详细行列式讲解

用高中數學從頭證明det(AB)=det(A)det(B)

行列式 - OI Wiki

后记——六亲不认,水火无敌

大约三个月之前,我写下了《有的放矢——一个OIer兼训诂学爱好者的线性代数观》,收获了一众读者的好评,同时也收到了部分批评意见。在此,我衷心地感谢大家!你们的支持和批评是我前行的动力!

而在那篇文章发出之后,机房大佬RpUtl便开始催促我写下它的续篇,这让我萌生了创作这篇关于行列式的文章的想法——在此衷心地感谢他!

(以下的内容是笔者私货,请读者自行评判)

混迹互联网多年,笔者对同济大学版《线性代数》的特点早有耳闻:将行列式放于开头,并因此向广大线性代数初学者直接引入排列和逆序数概念。这使得行列式概念对学习者来说像是天上掉下来的,虽然其隐隐约约地暗示行列式能解线性方程组,但却不明晰其原因。我听说这是因为在数学发展史上行列式早于矩阵乘法出现,好吧,我想,如果我编了教材,就把对数放在指数前边,让大家去操作动点去吧。

行列式这东西从名字开始就让人捉摸不透:你有行、有列,所以叫行列式?你是来干什么的?是来当一个有行有列的方块的?我看未必,你从出生就是冲着解方程去的,然而你不叫作“酷炫解方程决定子”之类的名字,却要叫做“行列式”。更别提你其实没有行和列,你是一个运算,或者说一个数,只有那个结果是你的,有行有列的其实是人家矩阵。啊,矩阵!如果我不知道数可以被放到矩阵这个方块里,我该如何接受它们能在行列式中被排列和逆序数操纵?行列式,你真的太坏了,矩阵的方括号已经很简约了,而你事事要争它一头,明明自己已经有了 \det 这种记法,却愣是要给自己夺得直线包裹住的记法——纯纯制造混乱,我该如何区分一阶矩阵的行列式和一个绝对值呢?

当然,我无法使用这一本《线性代数》,因为我不是高贵的大学生,只是一个高中 OIer。而我在上网搜索行列式相关知识时,也同样无法从中获取“行列式为什么要这么定义”的答案——以我的标准来看,互联网上不存在一篇关于“行列式入门”的文章,有的只是“行列式计算”。它们拿起行列式的定义,不管这东西是不是让读者莫名其妙地胆战心惊,就像干燥的豌豆一样吐出了好多关于它的性质,并且认为它们是不加证明的。因此,我决定书写这一篇文章,在从互联网的汪洋大海搜刮知识时把它们整理下来,补充它们的证明,从而铸造第一篇关于“行列式入门”的文章。

我觉得不是给初学者写的文章都不是给初学者写的,我自己是初学者,所以我猜这篇文章是给初学者写的。如果有初学者看不懂,请批评我。