∣ a 11 a 12 ⋯ a 1 n a 21 a 22 ⋯ a 2 n ⋮ ⋮ ⋱ ⋮ a n 1 a n 2 ⋯ a n n ∣ = ∑ ( − 1 ) t a 1 p 1 a 2 p 2 ⋯ a n p n \begin{vmatrix} {a_{11}}&{a_{12}}&{\cdots}&{a_1n}\\ {a_{21}}&{a_{22}}&{\cdots}&{a_2n}\\ {\vdots}&{\vdots}&{\ddots}&{\vdots}\\ {a_{n1}}&{a_{n2}}&{\cdots}&{a_{nn}}\\ \end{vmatrix}= \sum{(-1)^{t}}{a_{1p_{1}}a_{2p_{2}}}{\cdots}{a_{np_{n}}} ∣∣∣∣∣∣∣∣∣a11a21⋮an1a12a22⋮an2⋯⋯⋱⋯a1na2n⋮ann∣∣∣∣∣∣∣∣∣=∑(−1)ta1p1a2p2⋯anpn
标注:t: p 1 p 2 p 3 ⋯ p n {p_1}{p_2}{p_3}{\cdots}{p_n} p1p2p3⋯pn 的逆序数
p 1 p 2 p 3 ⋯ p n {p_1}{p_2}{p_3}{\cdots}{p_n} p1p2p3⋯pn从下标来看可以看作n个数的全排列,而t则是后面下标序列的逆序数,所以我们可以将他分成三个模块来实现,首先是求的我们所需的全排列序列,然后对该序列求逆序数,最后累加求和
Anaconda 3 + Python 3.6.5 + Jupyter
import numpy as np
import copy
从n个不同元素中任取m(m≤n)个元素,按照一定的顺序排列起来,叫做从n个不同元素中取出m个元素的一个排列。当m=n时所有的排列情况叫全排列。
公式:全排列数f(n)=n!(定义0!=1)
(深度优先搜索)采用递归的思路:先确定一个节点,然后后面的节点进行交换,在确定下一个节点,一层层递归,递归回溯时应将顺序交换回来,以便向其他子节点方向递归
# 全排列
def permutations(n):
arr = [x for x in range(n)]
result =[]
dfs(arr,0,len(arr),result)
return result
def dfs(arr, begin, end,result):
if begin == end:
result.append(copy.deepcopy(arr))
pass
else:
for i in range(begin,end):
arr[i],arr[begin] = arr[begin],arr[i]
dfs(arr,begin+1,end,result)
arr[i],arr[begin] = arr[begin],arr[i]
pass
pass
# 逆序数
def inverse(arr):
count = 0
for i in range(len(arr)):
for j in range(i):
if arr[j] > arr[i]:
count+=1
pass
pass
pass
return count
def det(matrix):
if matrix.shape[0]!=matrix.shape[1]:
print('此矩阵不是方阵!')
return
permutation = permutations(matrix.shape[0])
permutation = np.array(permutation)
result = 0
for i in range(len(permutation)):
a = 1
for j in range(matrix.shape[0]):
a*=matrix[j][permutation[i][j]]
result += pow(-1,inverse(permutation[i]))*a
return result
对以下方程组:
{ a 11 x 1 + a 12 x 2 + ⋯ + a 1 n x n = b 1 a 21 x 1 + a 22 x 2 + ⋯ + a 2 n x n = b 2 ⋯ ⋯ a n 1 x 1 + a n 2 x 2 + ⋯ + a n n x n = b n \begin{cases} a_{11}x_1 + a_{12}x_2 + {\cdots} + a_{1n}x_n = b_1\\ a_{21}x_1 + a_{22}x_2 + {\cdots} + a_{2n}x_n = b_2\\ {\cdots}{\cdots}\\ a_{n1}x_1 + a_{n2}x_2 + {\cdots} + a_{nn}x_n = b_n\\ \end{cases} ⎩⎪⎪⎪⎨⎪⎪⎪⎧a11x1+a12x2+⋯+a1nxn=b1a21x1+a22x2+⋯+a2nxn=b2⋯⋯an1x1+an2x2+⋯+annxn=bn
如果线性方程组的系数行列式D不为零,即:
D = ∣ a 11 ⋯ a 1 n ⋮ ⋱ ⋮ a n 1 ⋯ a n n ∣ ≠ 0 D=\begin{vmatrix} {a_{11}}&{\cdots}&{a_{1n}}\\ {\vdots}&{\ddots}&{\vdots}\\ {a_{n1}}&{\cdots}&{a_{nn}}\\ \end{vmatrix} {\neq} 0 D=∣∣∣∣∣∣∣a11⋮an1⋯⋱⋯a1n⋮ann∣∣∣∣∣∣∣=0
那么方程组有唯一解:
x 1 = D 1 D , x 2 = D 2 D , ⋯ , x n = D n D x_1 = \frac{D_1}{D} , x_2 = \frac{D_2}{D} , {\cdots} , x_n = \frac{D_n}{D} x1=DD1,x2=DD2,⋯,xn=DDn
其中 D j D_j Dj(j=1,2, ⋯ \cdots ⋯,n) 是把行列式D中第j列元素用方程组右端的常数项代替后所得到的n阶行列式,即:
D j = ∣ a 11 ⋯ a 1 , j − 1 b 1 ⋯ a 1 n ⋮ ⋮ ⋮ ⋮ a n 1 ⋯ a n , j − 1 b 1 ⋯ a n n ∣ D_j=\begin{vmatrix} {a_{11}}&{\cdots}&a_{1,j-1}&b_1&{\cdots}&a_{1n}\\ {\vdots}&&{\vdots}&{\vdots}&&{\vdots}\\ {a_{n1}}&{\cdots}&a_{n,j-1}&b_1&{\cdots}&a_{nn}\\ \end{vmatrix} Dj=∣∣∣∣∣∣∣a11⋮an1⋯⋯a1,j−1⋮an,j−1b1⋮b1⋯⋯a1n⋮ann∣∣∣∣∣∣∣
对此我们做出如下约定:
- d为系数矩阵作为函数的第一个参数
- b为方程组右端常数项组成的列向量作为函数的第二个参数
- d_i为公式中的 D j D_j Dj(j=1,2, ⋯ \cdots ⋯,n) 组成的三维矩阵
- 返回由结果 x i x_i xi(j=i,2, ⋯ \cdots ⋯,n) 组成的向量
实现代码:
def cramer(d,b):
if d.shape[0]!=d.shape[1]:
print('此矩阵不是方阵!')
return
if det(d) == 0:
print('系数方阵为0')
return
d_i = []
for i in range(b.shape[0]):
d_i.append(copy.deepcopy(d))
d_i[i][:,i] = b
pass
x = []
for i in range(b.shape[0]):
x.append(det(d_i[i]) / det(d))
print(x)
测试结果:
测试以下方程组:
{ 2 x + y + z = 15 x + 2 y + z = 16 x + y + 2 z = 17 \begin{cases} 2x + y + z = 15\\ x + 2y + z =16\\ x + y + 2z =17\\ \end{cases} ⎩⎪⎨⎪⎧2x+y+z=15x+2y+z=16x+y+2z=17
即:
[ 2 1 1 15 1 2 1 16 1 1 2 17 ] \left[ \begin{array}{ccc|c} 2&1&1&15\\ 1&2&1&16\\ 1&1&2&17 \end{array} \right] ⎣⎡211121112151617⎦⎤
索引函数的输入为:
d = ∣ 2 1 1 1 2 1 1 1 2 ∣ b = ∣ 15 16 17 ∣ d=\begin{vmatrix} 2&1&1\\ 1&2&1\\ 1&1&2 \end{vmatrix} \;\;\;\;\;\;\;\;\;\;\;\;\;\; b = \begin{vmatrix} 15\\16\\17 \end{vmatrix} d=∣∣∣∣∣∣211121112∣∣∣∣∣∣b=∣∣∣∣∣∣151617∣∣∣∣∣∣
预测结果:
x = ∣ 3 4 5 ∣ x = \begin{vmatrix} 3&4&5 \end{vmatrix} x=∣∣345∣∣
运行结果:
d = np.array([[2,1,1],[1,2,1],[1,1,2]])
b = np.array([15,16,17])
cramer(d,b)
[3.0, 4.0, 5.0] |