矩阵与高斯消元:数学算法在计算机领域的应用

5个4000比特大状态置换算法的设计与分析 下面是 5 个概念性、实验性的 4000 位可逆置换设计。它们都保证是双射,但未经过密码分析,不可直接用于生产系统。风格分别覆盖:三维 SPN、Feistel、可逆元胞自动机、ARX、宽轨迹/Keccak 式结构。 这 5 个设计分别代表了 SPN、Feistel、元胞自动机、ARX、宽轨迹 Keccak 五种不同风格,覆盖了主流大状态置换的构造思路。再次强调:它们只是实验性概念,若要用于实际协议,必须经过严格安全性分析。 阅读详情

一、概述和基本概念

矩阵,类似于在 C++ 中我们看到的二维数组。它有两个维度,行和列。下面是一个典型的矩阵:
M=[12342345445610111213] M= \begin{bmatrix} 1 & 2 & 3 & 4 \\ 2 & 3 & 4 & 5 \\ 4 & 4 & 5 & 6 \\ 10 & 11 & 12 & 13 \end{bmatrix} M=​12410​23411​34512​45613​​
我们可以对矩阵进行一些变换,前后矩阵不变,从而实现等量交换。

高斯消元,是解决 NNN 元一次方程组的高效方法。假设我们有如下的一个方程组:
{a1,1x1+a1,2x2+a1,3x3+⋯+a1,nxn=c1a2,1x1+a2,2x2+a2,3x3+⋯+a2,nxn=c2…am,1x1+am,2x2+am,3x3+⋯+am,nxn=cm \begin{cases} a_{1,1}x_1+a_{1,2}x_2+a_{1,3}x_3+\dots+a_{1,n}x_n=c_1 \\ a_{2,1}x_1+a_{2,2}x_2+a_{2,3}x_3+\dots+a_{2,n}x_n=c_2 \\ \dots\\ a_{m,1}x_1+a_{m,2}x_2+a_{m,3}x_3+\dots+a_{m,n}x_n=c_m \end{cases} ⎩⎨⎧​a1,1​x1​+a1,2​x2​+a1,3​x3​+⋯+a1,n​xn​=c1​a2,1​x1​+a2,2​x2​+a2,3​x3​+⋯+a2,n​xn​=c2​…am,1​x1​+am,2​x2​+am,3​x3​+⋯+am,n​xn​=cm​​
那么,使用 Gauss 消元可以在 O(n3)O(n^3)O(n3) 的时间复杂度内解决问题,相较于枚举每个 xxx 的朴素算法(时间复杂度为 O(kmn)O(kmn)O(kmn) ,其中 kkk 为 xxx 的值域大小, mmm 为方程组个数) ,时间复杂度得到了优化(尤其是 ∣k∣≤109|k| \le 10^9∣k∣≤109 等值域较大的时候)。

二、矩阵的基本操作

在接下来的叙述里,我们将默认采用 NNN 个矩阵 A1,A2,…,ANA_1,A_2,\dots,A_{N}A1​,A2​,…,AN​ 。

1. 矩阵运算

矩阵的加法:将矩阵的每个数分别相加。具体定义:设进行加法的两个矩阵分别为 A,BA,BA,B ,结果为矩阵 CCC ,则
∀1≤i,j≤n,Ci,j=Ai,j+Bi,j\forall 1 \le i,j \le n, C_{i,j}=A_{i,j}+B_{i,j}∀1≤i,j≤n,Ci,j​=Ai,j​+Bi,j​
举例:
[345123256]+[135246357]=[3+1=44+3=75+5=101+2=32+4=63+6=92+3=55+5=106+7=13] \begin{bmatrix} 3 & 4 & 5 \\ 1 & 2 & 3 \\ 2 & 5 & 6 \\ \end{bmatrix} + \begin{bmatrix} 1 & 3 & 5 \\ 2 & 4 & 6 \\ 3 & 5 & 7 \\ \end{bmatrix}= \begin{bmatrix} 3+1=4 & 4+3=7 & 5+5=10 \\ 1+2=3 & 2+4=6 & 3+6=9 \\ 2+3=5 & 5+5=10 & 6+7=13 \\ \end{bmatrix} ​312​425​536​​+​123​345​567​​=​3+1=41+2=32+3=5​4+3=72+4=65+5=10​5+5=103+6=96+7=13​​
求解的时间复杂度为 O(nm)O(nm)O(nm) ,其中 nnn 为矩阵列数, mmm 为矩阵行数。下同,不再赘述。

矩阵的乘法:这里非常有必要提一下。矩阵乘法的结果是目标值所在行的所有数分别乘以目标值所在列的所有数的和。设进行乘法的两个矩阵分别是 A(n×r),B(r×m)A(n \times r),B(r \times m)A(n×r),B(r×m) ,得到了矩阵 C(n×m)C(n \times m)C(n×m) ,则
∀1≤i,j≤n,Ci,j=∑k=1rAi,k⋅Bk,j\forall 1\le i,j\le n, C_{i,j}=\sum_{k=1}^r{A_{i,k} \cdot B_{k,j}}∀1≤i,j≤n,Ci,j​=k=1∑r​Ai,k​⋅Bk,j​
求解的时间复杂度为 O(n3)O(n^3)O(n3) 级别。
举例:
[345123256]×[135246357]=[72144212367210878156238] \begin{bmatrix} 3 & 4 & 5 \\ 1 & 2 & 3 \\ 2 & 5 & 6 \\ \end{bmatrix} \times \begin{bmatrix} 1 & 3 & 5 \\ 2 & 4 & 6 \\ 3 & 5 & 7 \\ \end{bmatrix}= \begin{bmatrix} 72 & 144 & 212 \\ 36 & 72 & 108 \\ 78 & 156 & 238 \end{bmatrix} ​312​425​536​​×​123​345​567​​=​723678​14472156​212108238​​

矩阵的幂:ANA^NAN 表示将同一个矩阵 AAA 连续乘以它自身 NNN 次。

根据以上定义,我们可以写出矩阵(matrix)结构体的基本内容,这里假设输入都合法:

struct Matrix
{
	int n, m;
	vector< vector<int> > matrix;
	
	Matrix(int n, int m) : n(n), m(m)
	{
		matrix.clear();
		for (int i = 0; i <= n; ++i)
		{
			vector<int> temp(m + 1);
			temp.clear();
			matrix.push_back(temp);
		}
	}
	
	Matrix(const Matrix& E) : n(E.n), m(E.m), matrix(E.matrix) { };
	
	Matrix operator+(Matrix b) const
	{
		int p = max(n, b.n);
		int q = max(m, b.m);
		Matrix c(p, q);
		for (int i = 1; i <= p; ++i)
		{
			for (int j = 1; j <= q; ++j)
			{
				c.matrix[i][j] = matrix[i][j] + b.matrix[i][j];
			}
		}
		return c;
	}
	
	Matrix operator*(Matrix b)
	{
		Matrix c(n, b.m);
		for (int i = 1; i <= n; ++i)
		{
			for (int j = 1; j <= b.m; ++j)
			{
				for (int k = 1; k <= n; ++k)
				{
				    c.matrix[i][j] += matrix[i][k] * b.matrix[k][j];
				}
			}
		}
		return c;
	}
	
	Matrix operator*(int b)
	{
		Matrix c(n, m);
		for (int i = 1; i <= n; ++i)
		{
			for (int j = 1; j <= m; ++j)
			{
                c.matrix[i][j] = matrix[i][j] * b;
			}
		}
		return c;
	}
};

2. 矩阵运算的性质

大写字母均代表矩阵,小写字母均代表数值。为方便推导,我们假设矩阵的大小均为 n×nn \times nn×n 。

(1) 交换律:

i) A+B=B+AA+B=B+AA+B=B+A

证明:令 C=A+BC=A+BC=A+B 。
∀1≤i,j≤n,Ci,j=Ai,j+Bi,j\forall 1 \le i,j \le n, C_{i,j}=A_{i,j}+B_{i,j}∀1≤i,j≤n,Ci,j​=Ai,j​+Bi,j​ ,
⇒Ci,j=Bi,j+Ai,j\Rightarrow C_{i,j}=B_{i,j}+A_{i,j}⇒Ci,j​=Bi,j​+Ai,j​ 。这就证明了 i 。

(2) 结合律:

ii) (A+B)+C=A+(B+C)(A+B)+C=A+(B+C)(A+B)+C=A+(B+C)
iii) (AB)⋅C=A⋅(BC)(AB) \cdot C=A \cdot (BC)(AB)⋅C=A⋅(BC)

证明:令 D=(A+B)+CD=(A+B)+CD=(A+B)+C 。
∀1≤i,j≤n,Di,j=(Ai,j+Bi,j)+Ci,j\forall 1 \le i,j \le n, D_{i,j}=(A_{i,j}+B_{i,j})+C_{i,j}∀1≤i,j≤n,Di,j​=(Ai,j​+Bi,j​)+Ci,j​
⇒Di,j=Ai,j+(Bi,j+Ci,j)\Rightarrow D_{i,j}=A_{i,j}+(B_{i,j}+C_{i,j})⇒Di,j​=Ai,j​+(Bi,j​+Ci,j​) 。这就证明了 ii 。
令 D′=(AB)⋅CD'=(AB) \cdot CD′=(AB)⋅C 。
∀1≤i,j≤n,Di,j′=(∑k=1nAi,k⋅Bk,j)Ci,j=∑k=1n(∑d=1nAi,d⋅Bd,j)⋅Ck,j=∑k=1n(∑d=1nBi,d⋅Cd,j)⋅Ak,j=(∑k=1nBi,k⋅Ck,j)Ai,j\forall 1 \le i,j \le n, D'_{i,j}=(\displaystyle\sum_{k=1}^n{A_{i,k} \cdot B_{k,j}})C_{i,j}=\displaystyle\sum_{k=1}^n{(\displaystyle\sum_{d=1}^n{A_{i,d} \cdot B_{d,j}}) \cdot C_{k,j}}=\displaystyle\sum_{k=1}^n{(\displaystyle\sum_{d=1}^n{B_{i,d} \cdot C_{d,j}}) \cdot A_{k,j}}=(\displaystyle\sum_{k=1}^n{B_{i,k} \cdot C_{k,j}})A_{i,j}∀1≤i,j≤n,Di,j′​=(k=1∑n​Ai,k​⋅Bk,j​)Ci,j​=k=1∑n​(d=1∑n​Ai,d​⋅Bd,j​)⋅Ck,j​=k=1∑n​(d=1∑n​Bi,d​⋅Cd,j​)⋅Ak,j​=(k=1∑n​Bi,k​⋅Ck,j​)Ai,j​ 。这就证明了 iii 。

重要推论:因为矩阵的乘法有结合律,所以
AN=∏i=1NA=∏i=1N2A⋅∏i=N2+1NAA^N=\prod^{N}_{i=1}A=\prod^\frac{N}{2}_{i=1}{A}\cdot \prod^N_{i=\frac{N}{2}+1}{A}AN=i=1∏N​A=i=1∏2N​​A⋅i=2N​+1∏N​A
因此,我们可以使用快速幂进行简便计算,将矩阵幂的复杂度由 O(n4)O(n^4)O(n4) 降至 O(n3log⁡n)O(n^3\log n)O(n3logn) 。
所以,我们可以添加一个 Matrix 类的成员函数:

Matrix pow(int b)
{
	Matrix c(n, m);
	Matrix a(n, m);
	memcpy(a.matrix, matrix, sizeof(matrix));
	for (; b; b >>= 1)
	{
		if (b & 1)
		{
			c = c * a;
		}
		a = a * a;
	}
	return c;
}

(3) 分配率:

iv) (A+B)C=AC+BC(A+B)C=AC+BC(A+B)C=AC+BC

证明:令 D=(A+B)CD=(A+B)CD=(A+B)C 。
∀1≤i,j≤n,Di.j=∑i=1n[(Ai,k+Bi,k)Ck,j]=∑i=1n(Ai,k⋅Ck,j+Bi,k⋅Ck,j)=∑i=1nAi,k⋅Ck,j+∑i=1nBi,k⋅Ck,j\forall 1 \le i,j \le n, D_{i.j}=\displaystyle\sum_{i=1}^n[(A_{i,k}+B_{i,k})C_{k,j}]=\displaystyle\sum_{i=1}^n(A_{i,k}\cdot C_{k,j}+B_{i,k}\cdot C_{k,j})=\sum_{i=1}^{n}{A_{i,k}\cdot C_{k,j}}+\displaystyle\sum_{i=1}^{n}{B_{i,k} \cdot C_{k,j}}∀1≤i,j≤n,Di.j​=i=1∑n​[(Ai,k​+Bi,k​)Ck,j​]=i=1∑n​(Ai,k​⋅Ck,j​+Bi,k​⋅Ck,j​)=i=1∑n​Ai,k​⋅Ck,j​+i=1∑n​Bi,k​⋅Ck,j​ 。这就证明了 iv 。

3. 特殊矩阵:单位矩阵

单位矩阵是一个正方形,记作 EEE ,其中从左上角开始到右下角结束的一条对角线上的值是 111 ,其余都是 000 。一个典型的单位矩阵如下:
E4=[1000010000100001] E_4= \begin{bmatrix} 1 & 0 & 0 & 0 \\ 0 & 1 & 0 & 0 \\ 0 & 0 & 1 & 0 \\ 0 & 0 & 0 & 1 \end{bmatrix} E4​=​1000​0100​0010​0001​​
单位矩阵具有如下性质:
v) ∀ matrix A,  AE=EA=A\forall \text{ matrix }A,\space\space AE=EA=A∀ matrix A,  AE=EA=A

证明:假设 P=AEP=AEP=AE , EEE 的大小为 n×nn \times nn×n 。
显然,有 ∀1≤i,j≤n, Pi,j=∑k=1nAi,k⋅Ek,j\forall 1 \le i,j \le n, \space P_{i,j}=\displaystyle\sum_{k=1}^n A_{i,k} \cdot E_{k,j}∀1≤i,j≤n, Pi,j​=k=1∑n​Ai,k​⋅Ek,j​ 。
因为在第 jjj 行中有且仅有第 jjj 个元素非 000 ,即 Ej,j=1E_{j,j} = 1Ej,j​=1 ,所以 Pi,j=(∑k=1, k≠jnAi,k⋅0)+Ai,j=Ai,jP_{i,j}=(\displaystyle\sum_{k=1,\space k\neq j}^n A_{i,k} \cdot 0)+A_{i,j}=A_{i,j}Pi,j​=(k=1, k=j∑n​Ai,k​⋅0)+Ai,j​=Ai,j​ ,所以 AE=AAE=AAE=A 。
由矩阵乘法的交换律,知 AE=EA=AAE=EA=AAE=EA=A 。这就证明了 v 。

4. 矩阵的行初等变换

(1)对换变换:交换矩阵的任意两行,矩阵不变。
(2)倍乘变换:将矩阵的某一行乘以一个常数,矩阵不变。
(3)倍加变换:在对矩阵的某一行进行倍乘变换后加到另一行的数上。
这三点将会被用在 Gauss 消元中。
实现对换变换、倍乘变换、倍加变换的例子如下:
对换变换:
[345123256]  ⟹  [345256123] \begin{bmatrix} 3 & 4 & 5 \\ 1 & 2 & 3 \\ 2 & 5 & 6 \\ \end{bmatrix} \implies \begin{bmatrix} 3 & 4 & 5 \\ 2 & 5 & 6 \\ 1 & 2 & 3 \\ \end{bmatrix} ​312​425​536​​⟹​321​452​563​​
倍乘变换:
[345123256]  ⟹  [34512341012] \begin{bmatrix} 3 & 4 & 5 \\ 1 & 2 & 3 \\ 2 & 5 & 6 \\ \end{bmatrix} \implies \begin{bmatrix} 3 & 4 & 5 \\ 1 & 2 & 3 \\ \bold{4} & \bold{10} & \bold{12} \\ \end{bmatrix} ​312​425​536​​⟹​314​4210​5312​​
倍加变换:
[345123256]  ⟹  [34512341012]  ⟹  [3455121541012] \begin{bmatrix} 3 & 4 & 5 \\ 1 & 2 & 3 \\ 2 & 5 & 6 \\ \end{bmatrix} \implies \begin{bmatrix} 3 & 4 & 5 \\ 1 & 2 & 3 \\ \bold{4} & \bold{10} & \bold{12} \\ \end{bmatrix} \implies \begin{bmatrix} 3 & 4 & 5 \\ \bold{5} & \bold{12} & \bold{15} \\ 4 & 10 & 12 \\ \end{bmatrix} ​312​425​536​​⟹​314​4210​5312​​⟹​354​41210​51512​​

三、 Gauss 消元的算法原理及过程

1. 基本定义

对于以下方程组:
{a1,1x1+a1,2x2+a1,3x3+⋯+a1,nxn=c1a2,1x1+a2,2x2+a2,3x3+⋯+a2,nxn=c2…am,1x1+am,2x2+am,3x3+⋯+am,nxn=cm \begin{cases} a_{1,1}x_1+a_{1,2}x_2+a_{1,3}x_3+\dots+a_{1,n}x_n=c_1 \\ a_{2,1}x_1+a_{2,2}x_2+a_{2,3}x_3+\dots+a_{2,n}x_n=c_2 \\ \dots\\ a_{m,1}x_1+a_{m,2}x_2+a_{m,3}x_3+\dots+a_{m,n}x_n=c_m \end{cases} ⎩⎨⎧​a1,1​x1​+a1,2​x2​+a1,3​x3​+⋯+a1,n​xn​=c1​a2,1​x1​+a2,2​x2​+a2,3​x3​+⋯+a2,n​xn​=c2​…am,1​x1​+am,2​x2​+am,3​x3​+⋯+am,n​xn​=cm​​
系数矩阵:由方程的系数 ai,1,⋯ ,ai,na_{i,1},\cdots,a_{i,n}ai,1​,⋯,ai,n​ 组成的矩阵,记为 MMM 。
增广矩阵:在系数矩阵的最右侧添加一列,为 cic_ici​ ,记为 M∣cM|cM∣c 。
Gauss 消元的算法过程在增广矩阵上进行。
例如,对于方程组:
{3x1+2x2=753x1+73x2=1007 \begin{cases} 3x_1 + 2x_2 = 7 \\ \frac{5}{3}x_1 + \frac{7}{3}x_2 = \frac{100}{7} \end{cases} {3x1​+2x2​=735​x1​+37​x2​=7100​​
它的系数矩阵、增广矩阵分别是:
[325373],[32753731007] \begin{bmatrix} 3 & 2 \\ \frac{5}{3} & \frac{7}{3} \\ \end{bmatrix}, \begin{bmatrix} 3 & 2 & 7 \\ \frac{5}{3} & \frac{7}{3} & \frac{100}{7} \\ \end{bmatrix} [335​​237​​],[335​​237​​77100​​]

2. 补充知识

主元:在一个矩阵中,对于该矩阵的某一行(指定的),从左到右第一个非 000 的数字就是主元。
行阶梯型矩阵:满足以下 333 个性质的矩阵就是行阶梯型矩阵:

  • ∀1≤i≤n,i∈Z\forall 1 \le i \le n, i \in \bold{Z}∀1≤i≤n,i∈Z ,第 iii 行的主元永远在第 i+1i+1i+1 行主元的左上方。
  • ∀1≤i≤n,i∈Z\forall 1 \le i \le n, i \in \bold{Z}∀1≤i≤n,i∈Z ,第 iii 行的主元下方均为 000。这一性质其实可以由上面的那一条推出。
  • 所有非零行都在所有零行之上。这一性质也可以由第一条推出。

一个典型的行阶梯型矩阵如下,加粗的为主元,可以观察到以上三条性质:
[31023510073420004640000010000000] \begin{bmatrix} \bold{3} & 10 & 2 & 3 & 5 & 1 \\ 0 & 0 & \bold{7} & 3 & 4 & 2 \\ 0 & 0 & 0 & \bold{4} & 6 & 4 \\ 0 & 0 & 0 & 0 & 0 & \bold{10} \\ 0 & 0 & 0 & 0 & 0 & 0 \end{bmatrix} ​30000​100000​27000​33400​54600​124100​​

简化行阶梯型矩阵:在行阶梯型矩阵的基础上满足以下性质:

  • 每一个非 000 行的主元一定是 111 。
  • 每一个主元 111 是该行唯一的非 000 元素。

Gauss 消元的目标就是把一个矩阵简化为行阶梯型矩阵。

3. Gauss 消元算法的主要过程及其对应在方程组中操作的实际意义

假设我们的增广矩阵 AAA 是 n×mn \times mn×m 的。
先写出 Gauss 消元算法的主要流程:

  1. 枚举列号 ∀1≤c≤m∈Z\forall 1 \le c\le m \in \bold{Z}∀1≤c≤m∈Z 。
  2. 找到主元。假设当前是第 ccc 列,我们在 [1,c−1][1,c-1][1,c−1] 列这一范围内已经找到了 w−1w-1w−1 个主元,根据行阶梯型矩阵的定义以及性质,下一列的主元一定在上一列的主元的右下方,即一定在第 ccc 列,第 [w,n][w, n][w,n] 行范围内。故应该在 [w,n][w,n][w,n] 行范围内寻找主元。该主元应绝对值最大,找到的主元的绝对值 ∣W∣=max⁡w≤i≤n,w∈Z{∣Ai,c∣}|W|=\displaystyle\max_{w \le i \le n,w\in\bold{Z}}\{|A_{i,c}|\}∣W∣=w≤i≤n,w∈Zmax​{∣Ai,c​∣}
  3. 如果我们找到的 Aa,b=0A_{a,b}=0Aa,b​=0 ,说明继续操作没有意义,跳过当前列,下一列寻找。否则,将当前找到的主元所在行与第 www 行做对换变换。因此,该操作并没有改变矩阵,只是将矩阵化为另一种形式,方便统计。变换后,主元所在行变成了第 www 行。
  4. 对第 www 行做倍乘变换。∀1≤i≤m,Aw,i←Aw,i×1Aw,c\forall 1 \le i \le m, A_{w,i} \leftarrow A_{w,i} \times \displaystyle\frac{1}{A_{w,c}}∀1≤i≤m,Aw,i​←Aw,i​×Aw,c​1​ ,相当于在方程组中将等式两边的值都除以 Aw,cA_{w,c}Aw,c​ ,即找到的主元。
  5. 消元。这是 Gauss 消元算法中最主要的步骤。主要目的是将第 ccc 列除主元所在位置 (w,c)(w,c)(w,c) 之外的所有元素变为 000 。为确保矩阵前后相同,我们对矩阵进行倍加变换。假设我们当前的位置是 (i,j)(i,j)(i,j) ,满足 i≠wi \neq wi=w 。根据简化行阶梯型矩阵的性质,可知 jjj 只需要在 w≤j≤m, j∈Zw \le j \le m,\space j \in\bold{Z}w≤j≤m, j∈Z 的范围内枚举即可,因为 ∀1≤j<w,Ai,j=0\forall 1 \le j < w, A_{i,j}=0∀1≤j<w,Ai,j​=0 恒成立(简化行阶梯型矩阵性质 2)。倍加变换的主要过程如下:当前枚举到 (i,j)(i,j)(i,j) ,主元位置为 (c,w)(c,w)(c,w) ,对于第 www 行的所有元素,应该乘以 Ai,cAw,c\displaystyle\frac{A_{i,c}}{A_{w,c}}Aw,c​Ai,c​​ 。推导过程类似于解方程组的思路,假设我们有一个如下的方程组:
    {4x+2y=64x+3y=7 \begin{cases} 4x+2y=6 \\ 4x+3y=7 \\ \end{cases} {4x+2y=64x+3y=7​
    那么我们一定会尝试去消去 4x4x4x ,这就是加减消元法(使用了初中数学七年级下-二元一次方程组的知识)。解得: {x=1y=1\begin{cases}x=1\\y=1\end{cases}{x=1y=1​ 。如果将它化为增广矩阵,那么将会等于 [426437]\begin{bmatrix}\bold{4} & 2 & 6 \\ \bold{4} & 3 & 7\end{bmatrix}[44​23​67​] ,主元在前面用粗体表示,如果我们尝试让第 111 列的所有元素变成 000 ,那么我们会让第一行的所有元素乘以 44=1\frac{4}{4}=144​=1 再减去第二行的所有元素。注意,分母的 444 代表的是 (1,1)(1,1)(1,1) 位置的元素,而分子的 444 则代表的是 (1,2)(1,2)(1,2) 位置的元素。增广矩阵会变成:[426011]\begin{bmatrix}4 & 2 & 6 \\ 0 & 1 & 1\end{bmatrix}[40​21​61​] ,此时消元的目的已经达到。
    将这个性质推广到 AAA ,则可以得出 ∀(i,j)∈A\forall (i,j) \in A∀(i,j)∈A , Ai,jA_{i,j}Ai,j​ 应该减去 Ai,cAw,c⋅Aw,cAw,j=Ai,c⋅Aw,j\frac{A_{i,c}}{A_{w,c}}\cdot \frac{A_{w,c}}{A_{w,j}}=A_{i,c}\cdot A_{w,j}Aw,c​Ai,c​​⋅Aw,j​Aw,c​​=Ai,c​⋅Aw,j​ 。为方便记忆,可以观察公式,行和列已经用 w,cw,cw,c 给定,将变量 i,ji,ji,j 按照行和列的变化插入即可。
  6. 方程组的解即为矩阵的最后一列,x1,x2,…x_1,x_2,\dotsx1​,x2​,… 与 An,1,An,2,…A_{n,1},A_{n,2},\dotsAn,1​,An,2​,… 一一对应。

用一些例子来更好理解 Gauss 消元算法:
{4x1+2x2+3x3=152x1+2x2+4x3=195x1+6x2+7x3=29[423152241956729]  ⟹  对换变换[567292241942315]  ⟹  倍乘变换[165752952241942315]  ⟹  倍加变换[165752950−25−137542315]… \begin{cases} 4x_1+2x_2+3x_3=15 \\ 2x_1+2x_2+4x_3=19 \\ 5x_1+6x_2+7x_3=29 \\ \end{cases} \\ \begin{bmatrix} 4 & 2 & 3 & 15 \\ 2 & 2 & 4 & 19 \\ \bold{5} & 6 & 7 & 29 \\ \end{bmatrix}\stackrel{对换变换}{\implies} \begin{bmatrix} \bold{5} & 6 & 7 & 29 \\ 2 & 2 & 4 & 19 \\ 4 & 2 & 3 & 15 \\ \end{bmatrix}\stackrel{倍乘变换}{\implies} \begin{bmatrix} \bold{1} & \frac{6}{5} & \frac{7}{5} & \frac{29}{5} \\ 2 & 2 & 4 & 19 \\ 4 & 2 & 3 & 15 \\ \end{bmatrix}\stackrel{倍加变换}{\implies} \\ \begin{bmatrix} \bold{1} & \frac{6}{5} & \frac{7}{5} & \frac{29}{5} \\ \bold{0} & \bold{-\frac{2}{5}} & \bold{-1} & \bold{\frac{37}{5}} \\ 4 & 2 & 3 & 15 \\ \end{bmatrix} \dots ⎩⎨⎧​4x1​+2x2​+3x3​=152x1​+2x2​+4x3​=195x1​+6x2​+7x3​=29​​425​226​347​151929​​⟹对换变换​​524​622​743​291915​​⟹倍乘变换​​124​56​22​57​43​529​1915​​⟹倍加变换​​104​56​−52​2​57​−13​529​537​15​​…

主要代码(在 Matrix 结构体中):

void Gauss()
{
	int w = 1;
	for (int c = 1; c <= m; ++c)
	{
		int temp = w;
		for (int i = w + 1; i <= n; ++i)
			if (abs(a[temp][c]) < abs(a[i][c]))
				temp = i;
		if (abs(a[temp][c]) < eps) continue;
		for (int i = c; i <= m; ++i) swap(a[temp][i], a[w][i]);
		for (int i = m; i >= c; --i) a[w][i] /= a[w][c];
		for (int i = 1; i <= n; ++i)
		{
			if (i == w) continue;
			for (int j = m; j >= c; --j)
				a[i][j] -= a[i][c] * a[w][j];
		}
	}
}

注:本文章所有代码未经调试及编译,如有 Bug ,欢迎在评论区指出,必互关 。

线性代数零基础入门与典型习题精讲实战 对于方阵 $A$,若存在非零向量 $\mathbf{v}$ 和标量 $\lambda$,使得:$$$$则 $\lambda$ 是特征值,$\mathbf{v}$ 是对应特征向量。求解步骤:构造特征方程:$\det(A - \lambda I) = 0$解多项式得特征值;对每个 $\lambda$,解 $(A - \lambda I)\mathbf{v} = 0$ 得特征向量。例:$$$$ 阅读详情

相关推荐

ESP32 BLE Mesh Provisioner实战:手把手教你用ESP-IDF配网智能灯泡(附常见错误排查)

本文提供了一份基于ESP-IDF的ESP32 BLE Mesh Provisioner实战指南,详细解析了配网器的核心角色与工作流程。文章手把手教你从工程搭建、代码初始化到核心回调解析,并重点针对常见的‘Model not bound to AppKey’等错误提供了深度排查思路与解决方案,帮助你构建一个稳定可靠的智能照明网关。

desk3的博客 513

加深深度学习矩阵计算理解--用人类直觉 走进线性代数(非应试)

1、向量是什么?①数学角度定义:向量(vector)又称矢量,在数学中也称为欧几里得向量、几何向量,是既有大小(用一个非负数表示)又有方向的量。向量的大小是代数特征,方向是几何特征。向量可以用有向线段来表示,有向线段的长度表示向量的大小,有向线段箭头所指的方向表示向量的方向。表示方法:向量可以用符号来表示,如、或等(手写时常用带箭头的小写字母表示,如)。也可以用有向线段的两个端点来表示,如向量AB(读作AB向量),表示从点A指向点B的向量。

m0_56243424的博客 1773

用SOLIDWORKS从零画一个履带机器人,手把手教你搞定底盘和传动

本文详细介绍了如何使用SOLIDWORKS从零开始设计履带式机器人,重点讲解底盘结构优化和传动系统设计的关键步骤。通过七个阶段的实战指南,包括前期规划、底盘建模、驱动系统装配、履带生成、动态模拟等,帮助工程师和爱好者掌握履带机器人的核心设计技巧,提升地形适应能力和动力效率。

weixin_30872499的博客 632

矩阵运算在数据分析中的应用

定义: 矩阵是由数字按照长方形排列成的数表,是数学和计算机领域中常用的数据结构。元素: 矩阵中的每个数称为元素,可以是整数、实数或复数。

技术研究中心 900

Ambari 3.0.0 + BigTop 3.3.0 源码编译与集群部署指南(Kylin V10 / aarch64)

仅仅是针对“应用商店目录(Applications Catalog)”的一个外围附属子模块(它不是 YARN 监控大盘,不影响 YARN UI 网页的主体使用),我们可以采用。自带的 Node 二进制是 x86_64 版本,在 ARM64(aarch64)容器上无法执行(Exit value: 126)。:Ambari Server/Agent 使用 JDK 17,BigTop 大数据组件(Hadoop/HBase/Spark 等)使用 JDK 8。,源码中包含 x86 特定的原生二进制文件。

amumu1992的博客 481

YonBIP 3.0 报表开发+报表超链接

用友报表开发

m0_55096250的博客 1757

视频隐私脱敏工程化:CSRT/KCF追踪算法在本地推理中的实现与边界

在短视频内容合规审查中,动态遮挡(Dynamic Masking)是高频且高耗时的环节。传统手动关键帧打码不仅效率低下,且在目标快速移动或遮挡时极易出现遮罩漂移。本文从计算机视觉工程角度,解析基于CSRT与KCF算法的目标追踪方案在视频隐私处理中的技术路径、性能权衡及落地实践。

Mysssone的博客 185

瑞芯微RK3576开发实战:固件烧录与内核启动的典型问题解析

本文详细解析了瑞芯微RK3576开发板在固件烧录与内核启动过程中遇到的典型问题及解决方案。从开发工具版本检查、DDR配置调整到内核启动异常的设备树适配和电源管理问题,提供了系统性的调试方法和实用技巧,帮助开发者高效解决RK3576开发中的常见挑战。

weixin_33700350的博客 454

【算法拾光】链表 哈希表|K个一组翻转链表 + 两数之和

K个一组翻转链表需分段反转,借助哑节点与前驱指针维护连接,避免断链;两数之和利用哈希表实现O(1)查找,空间换时间,高效定位目标组合。前者考察链表指针操作,后者聚焦映射关系构建,均为面试高频题。

wuqingyigexiaoba的博客 274

基于simulink的软开关技术的三相逆变器仿真

三相逆变器中的软开关技术(Soft Switching Techniques)旨在减少开关损耗,提高效率,并降低电磁干扰(EMI)。实现软开关通常涉及使用谐振电路或准谐振电路来确保开关器件在零电压(Zero Voltage Switching, ZVS)或零电流(Zero Current Switching, ZCS)条件下进行切换。下面将详细介绍如何在Simulink中进行基于软开关技术的三相逆变器仿真设计。

xiaoheshang_123的博客 162

FineBI学习总结

交叉表:一组作为行标题显示在表的左部,另一组作为列标题显示在表的顶部。连接到数据,如果数据不满足数据分析的需求,先进行自助数据集处理。数据集分类:DB表、SQL、Excel、自助数据集。分组表:将报表中的数据按相同项合并为一组显示。1、数据准备2、制作仪表板3、分享仪表板。左合并:保留左边全部数据,合并右边。右合并:保留右边全部数据,合并左边。上下拼接:上下拼接到一张表数据。3、如何实现拼表:多表拼一张。分组–业务包–数据集–字段。字段分类:数值、文本和日期。目录–仪表板–数据准备。维度:文本和日期类型。

Rsun2018的博客 1561

排序算法深度笔记(下):非比较类排序的线性突破与工程边界

排序算法时间复杂度额外空间复杂度稳定性是否基于比较选择排序O(N^2)(O(1))不稳定是冒泡排序O(N^2)(O(1))稳定是插入排序O(N^2)(O(1))稳定是归并排序O(N\log N)(O(N))稳定是快速排序O(N\log N)O(log N)不稳定是堆排序O(N\log N)O(1)不稳定是计数排序(O(N + M))O(M))稳定否基数排序O(N)稳定否桶排序平均O(N) / 最坏O(N^2)

2401_87069538的博客 557

IEM模型,地表粗糙度模拟

利用微波反演土壤水分时候,利用IEM模型可以实现对随机地表的模拟

算法日常・每日刷题--<动态规划>42

本题为“不相交的线”,与最长公共子序列问题相似。使用动态规划求解:定义 dp[i][j] 表示 nums1[0:i] 与 nums2[0:j] 的最大不相交连线数。若元素相等,则继承左上值加1;否则取上方或左方最大值。最终返回 dp[m][n],即两数组的最大不相交连线数。时间复杂度 O(mn),空间复杂度 O(mn)。

2503_92261635的博客 19

android 蓝牙通讯demo

android 下蓝牙通讯demo,实现了发现蓝牙,使能蓝牙,通过蓝牙发送消息。

Data-Structures-and-Algorithm-Analysis-in-Java.pdf

作者: Weiss, Mark A. 出版社: Addison Wesley Data Structures and Algorithm Analysis in Java is an “advanced algorithms” book that fits between traditional CS2 and Algorithms Analysis courses. In the old ACM Curriculum Guidelines, this course was known as CS7. This text is for readers who want to learn good programming and algorithm analysis skills simultaneously so that they can develop such programs with the maximum amo...

C语言程序设计题|有序数组插入数字冒泡排序

题目要求将一个数插入有序数组末尾,并用冒泡排序实现整体升序。代码先将输入数存入数组最后位置,再通过双重循环进行冒泡排序,每轮将较大元素向后移动,最终输出11个升序元素。该方法虽时间复杂度为O(n²),但符合题目要求,逻辑清晰,适合初学者理解排序原理。

2301_81429079的博客 643

【算法拾光】模拟|外观数列 + 数青蛙

本文总结两道模拟题解法:外观数列通过迭代统计连续数字个数生成下一项,关键在于处理末尾字符;数青蛙则模拟青蛙叫声“croak”状态转移,维护各阶段青蛙数量,记录最大并发数并确保全部完成。共性在于严格遵循流程、细致处理边界与非法情况,锻炼字符串遍历与状态管理能力。

wuqingyigexiaoba的博客 367

牛客周赛165C题(前后缀性质,递推,排序,枚举)

题目大意:给定长度为 `n` 的数组,选择 `k ∈ [1,n]`,将前 `k` 个元素整体翻转,后面的元素不变。要求操作后的整个数组非递减,统计满足条件的 `k` 的数量。题目链接:https://ac.nowcoder.com/acm/contest/141721/C。时间复杂度:O(nlogn)

2501_94316951的博客 164

【数据结构-3】算法美学之降复杂度

在while循环的循环体内,首先用临时变量保存最后一个位置的数据,再通过for循环把所有元素往后移动一位,最后把tmp中保存的值放到下标为0的位置上去。方法二的思路是:创建新数组,让原数组中后k个数据移动到新数组中前面的位置,让原数组中前numsSize-k个数据移动到新数组中后面的位置,这。这段代码的思路是:三次逆置,第一次逆置前numsSize-k个数据,第二次逆置后k个数据,最后整体逆置。这篇博文分享一道解法不一的算法题,求解过程的目的在于降低算法的时间复杂度,题源力扣。,属于空间换时间的操作。

weixin_44218929的博客 81

算法日常・每日刷题--<动态规划>32

给定严格递增的正整数数组,求最长斐波那契子序列长度。使用二维DP,dp[i][j]表示以arr[i]、arr[j]为最后两项的序列长度,初始化均为2。通过哈希表快速查找前一项target = arr[j] - arr[i],若存在且下标小于i,则状态转移:dp[i][j] = dp[k][i] + 1。遍历更新全局最大长度,最终若结果小于3则返回0。时间复杂度O(n²),空间复杂度O(n²)。

2503_92261635的博客 177

算法札记:几何分布在算法题UVA1262的运用

集卡问题求解核心:将集齐n种优惠券的过程分为n个阶段,每个阶段期望购买次数为 $ \frac{n}{k} $(k为剩余种类数),总期望为 $ n \cdot H_n $(调和数)。通过自洽方程推导单阶段期望,无需几何分布或无穷级数,逻辑清晰且适用于大一水平。例如,n=5时期望约11.42,非5。题目要求以带分数形式输出精确结果,算法上需累加分数并化简。

Keven_11的博客 317

不同的二叉搜索树

互不相同的二叉搜索树的种数,以 j (1<=j<=i)为头节点,左子树是 j-1 个数,右子树就是 i - (j - 1) -1 = i - j个数。所以dp[3] = dp[0] * dp[2] + dp[1] * dp[1] + dp[2] * dp[0]头1 = 左子树0节点 * 右子树2节点,二叉搜索树就是排序树,左子树<根节点<右子树,左右子树也满足左子树<根节点<右子树。头2 = 左子树1节点 * 右子树1节点。所以dp[i] += dp[j-1] * dp[i-j]个节点组成且节点值从。

qq_44721738的博客 150

SSL证书选RSA还是ECDSA:公钥算法、CA签名与兼容性怎么核对

申请SSL证书时,RSA和ECDSA该怎么选?先分清站点公钥算法、CA签名算法和TLS实际兼容性,再用隔离OpenSSL实验读取两类材料,核对申请、续期和部署交接,避免只看Signature Algorithm就选错。

谁呀!的博客 394

从曲线到储层:Techlog/KAPPA 全流程算法、UltraLAB 选型与本地 AI 部署实战

以高频 CPU 保证交互,以充足内存承载多井与多任务,以 NVMe 打通项目和知识库 I/O,再按本地模型、上下文与并发配置 GPU。对 UltraLAB 用户而言,更合理的采购方式是带着真实项目做选型:一组典型井、一套完整解释模板、一个目标大模型、一次多人并发测试。用实测结果确定配置,才能把预算转化为解释效率,而不是闲置算力。软件模块、操作系统与许可条件以厂商当前正式说明为准;硬件建议需结合项目实测。AI 输出只能作为辅助证据,不能替代岩石物理与油藏工程专业审核。

wdf8088的博客 164

【Deep-OC-SORT 01】多轨迹算法Deep-OC-SORT源码分析

本工程基于Deep-OC-SORT核心模块,重构并适配了EmbeddingComputer(外观特征提取)、CMCComputer(相机运动补偿)与OCSort(主跟踪器)三类。前者实现整框/网格模式的特征提取与L2归一化;后者通过稀疏光流或SIFT匹配估计仿射变换,补偿相机运动;主跟踪器融合IoU、外观相似度与方向一致性,支持模块开关与自定义组件,实现高效多目标跟踪。

Jayson 博客 331

C++ 标准库算法全景指南

本文系统梳理C++标准库<algorithm>与<numeric>中100+算法,按功能分为非修改、修改、排序、二分查找、归并、堆、极值、字典序、排列及数值操作十大类,涵盖典型用法与时间复杂度。结合C++20范围(ranges)与投影特性,实现更简洁高效的代码。

sss123ddd的博客 266

算法日常・每日刷题--<动态规划>41

给定两个字符串text1和text2,求其最长公共子序列长度。使用动态规划,定义dp[i][j]为text1前i个字符与text2前j个字符的最长公共子序列长度。若字符相等,则dp[i][j] = dp[i-1][j-1] + 1;否则取舍弃一方的最大值:dp[i][j] = max(dp[i-1][j], dp[i][j-1])。最终返回dp[m][n]。时间复杂度O(mn),空间复杂度O(mn)。

2503_92261635的博客 135
上一篇: KMP 算法:解决字符串匹配问题的高效算法
下一篇: CSP-S 难度的数学方法讲解:分解质因数的运用、欧拉函数、逆元、组合数
Aobing_peterJr
博客等级 码龄2年 128粉丝 18原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

当前余额3.43元 前往充值 >
需支付:10.00元
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付元
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值