动态规划之矩阵连乘

思考:

  三个矩阵A,B,C的阶分别是 a 0 ∗ a 1 , a 1 ∗ a 2 , a 2 ∗ a 3 a_0*a_1,a_1*a_2,a_2*a_3 a0a1,a1a2,a2a3 ,从而(AxB)xC和Ax(BxC)的乘法次数是 a 0 ∗ a 1 ∗ a 2 + a 0 ∗ a 2 ∗ a 3 , a 1 ∗ a 2 ∗ a 3 + a 0 ∗ a 1 ∗ a 3 a_0*a_1*a_2+a_0*a_2*a_3,a_1*a_2*a_3+a_0*a_1*a_3 a0a1a2+a0a2a3,a1a2a3+a0a1a3,二者一般是不相等的。则对于n个矩阵的连乘, A 1 ∗ A 2 ⋯ ∗ A n A_1*A_2\dots*A_n A1A2An,如何改变计算次序,使得乘法次数计算量最小呢?

例如:

A1={30x35} ; A2={35x15} ;A3={15x5} ;A4={5x10} ;A5={10x20} ;A6={20x25} ;

结果为:((A1(A2A3))((A4A5)A6)) 最小的乘次为15125。

思路:

  设A[i:j]为矩阵 A i ∗ A i + 1 ⋯ ∗ A j A_i*A_{i+1}\dots*A_j AiAi+1Aj的连乘积,即从Ai到Aj的连乘积,其中,0 <= i <= j <= n-1

设m[i][j]为计算A[i:j]的最小乘次,所以原问题的最优值为m[0][n-1]。

  • 当 i==j 时,单一矩阵,无需计算。 m [ i ] [ i ] = 0 , i = 0 , 1 … , n − 1 m[i][i]=0,i=0,1\dots,n-1 m[i][i]=0i=0,1,n1
  • 当 i < j 时,利用最优子结构,计算 m [ i ] [ j ] m[i][j] m[i][j]。即寻找断开位置k(i <= k < j),使得 m [ i ] [ k ] + m [ k + 1 ] [ j ] + P i ∗ P k + 1 ∗ P j + 1 m[i][k]+m[k+1][j]+P_i*P_{k+1}*P_{j+1} m[i][k]+m[k+1][j]+PiPk+1Pj+1最小。

公式如下:
在这里插入图片描述
完整代码如下:

class Matrix:
  def __init__(self, row_num=0, col_num=0, matrix=None):
    if matrix != None:
      self.row_num = len(matrix)
      self.col_num = len(matrix[0])
    else:
      self.row_num = row_num
      self.col_num = col_num
    self.matrix = matrix
def matrix_chain(matrixs):
	matrix_num = len(matrixs)
	count = [[0 for j in range(matrix_num)] for i in range(matrix_num)]
	flag = [[0 for j in range(matrix_num)] for i in range(matrix_num)]
	for interval in range(1, matrix_num + 1):
		for i in range(matrix_num - interval):
			j = i + interval
			count[i][j] = count[i][i] + count[i + 1][j] + matrixs[i].row_num * matrixs[i + 1].row_num * matrixs[j].col_num
			flag[i][j] = i
			for k in range(i + 1, j):
				temp = count[i][k] + count[k + 1][j] + matrixs[i].row_num * matrixs[k + 1].row_num * matrixs[j].col_num
				if temp < count[i][j]:
					count[i][j] = temp	
					flag[i][j] = k
	traceback(0, matrix_num - 1, flag)
	return count[0][matrix_num - 1]

def traceback(i, j, flag):
	if i == j:
		return
	if j - i > 1:
		print(str(i + 1) + '~' + str(j + 1), end=': ')
		print(str(i + 1) + ":" + str(flag[i][j] + 1), end=',')
		print(str(flag[i][j] + 2) + ":" + str(j + 1))
	traceback(i, flag[i][j], flag)
	traceback(flag[i][j] + 1, j, flag)
	

def main():
	matrixs = [Matrix(30, 35), Matrix(35, 15), Matrix(15, 5), Matrix(5, 10), Matrix(10, 20), Matrix(20, 25)]
	result = matrix_chain(matrixs)
	print(result)

if __name__ == '__main__':
	main()

运行结果为:

1~6: 1:3,4:6
1~3: 1:1,2:3
4~6: 4:5,6:6
15125

表示计算顺序为 ( ( A 1 ( A 2 A 3 ) ) ( ( A 4 A 5 ) A 6 ) ) ((A1(A2A3))((A4A5)A6)) ((A1(A2A3))((A4A5)A6))

你可能感兴趣的:(面试总结)