算法之动态规划-矩阵链相乘(matrix-chain multiplication)

Matrix-chain multiplication

给定一串矩阵 A1,A2...An,计算矩阵的值:A1A2A3..An。对于这串矩阵序列,不同的加括号方式,会导致截然不同的计算量。我们需要做的就是计算出如何加括号,达到最少计算量。

使用动态规划求解

first step: Characterize the structure of an optimal solution

数学定义:Ai..j : 矩阵乘—–AiAi+1Aj
存在k 使得ik<j
Aij 划分为 AikA(k+1)j
假设此时的k正好为最优划分,使得Aij矩阵相乘的规模最小

反证: 如果此时k对原来矩阵序列的划分不是最优的,则肯定存在另一个k,使得划分为最优:与假设矛盾。

second step: Recursively define the value of an optimal solution

现在我们定义递归求解这个子问题:Aij 为: 矩阵AiAi+1Aj (1ijn)

数学定义:M[i,j] = Aij 的最小矩阵乘规模
定义数组P,使得矩阵Ai的纬度为 = p[i1]p[i]p[i1]代表矩阵的行, p[i]代表矩阵的列)
如图1:
这里写图片描述
A3 的行下标为 p[2]=15 列下标为p[3]=5

  • i=j : Aij=Ai,单个矩阵,所以M[i,j]=0

  • i<j : Aij可分为Aik的矩阵乘规模数加上Ak+1Aj的矩阵乘规模数,再加上两个分矩阵的相乘规模数
    数学表达式为:M[i,j]=M[i,k]+M[k+1,j]+pi1pkpj
    重点理解pi1pkpj表达的意思:现在M[i,k]可理解为最终行下标为i,列下表为k的矩阵;M[k+1,j]可理解为最终行下标为k+1,列下表为j的矩阵;再把这两个矩阵相乘,也就是等同于两个矩阵相乘的规模数,再结合图一,得出结果——pi1pkpj

third step: Compute the value of an optimal solution

  • 递归算法:
matrix(p,i,j) {
  if i == j
     m[i,j] = 0
     retrun m[i,j]
  m[i,j] = 999999999999
  for k = i to j - 1
    temp = matrix(p,i,k) + matrix(p,k+1,j) + p[i-1]p[k]p[j]
    if temp < m[i,j]
      m[i,j] = temp
  return m[i,j]
}

下面看一个例子:对4个矩阵链的划分
图2:
recursive-matrix
- 动态规划:自顶向下
基本思路为:用数组保存下计算了的值,这样就避免了大量的重复计算。这也是动态规划的精髓所在,以空间换时间。

s[m,n]代表Am··n最优划分位置为s[m,n],记录下最优划分的位置
memory-matrix(p) {
  n = p.length - 1
  let s[n,n] be a global array
  let m[n,n] be a new array
  for i = 1 to n
    for j = i to n
      m[i,j] = 999999999
  return look-chain(m,p,1,n)  
}

look-chain(m,p,i,j) {
  if m[i,j] < 9999999999
    return m[i,j]
  if i == j
    m[i,j] = 0
  else for k = i to j - 1
         q = look-chain(m,p,j,k) + matrix(m,p,k+1,j) +p[i-1]p[k]p[j]
         if(q < m[i,j])
           m[i,j] = q
           s[i,j] = k
  return m[i,j]
}

At last:Construct an optimal solution from computed information

递归输出

printPartition(s,i,j) {
  if i == j
    print "Ai"
  else print "("
    printPartition(s,i,s[i,j])
    printPartition(s,s[i,j]+1,j)
    print")"
}
阅读更多
换一批

没有更多推荐了,返回首页