1.问题提出
- 软件行业中客户总是在变更需求
银行对我们公司开发的乘法模块还不满意。他们的真实想法并不是实现两个矩阵的乘法,而是是能一次够实现多个矩阵按照算法运算法则的乘法,因此要求我们进一步改进我们的系统,实现多个矩阵的连乘功能,并且需要看到我们设计的程序能够满足他们的运行效率要求时才付二期款。
2.关键计算问题
- 给定n个矩阵{,,。。。}, 其中 与 是可乘的,i=1,2,…n-1。 考察这n个矩阵的连乘积
… - 由于矩阵乘法满足结合律,所以计算矩阵的连乘可以有许多不同的计算次序。这种计算次序可以用加括号的方式来确定
- 若一个矩阵连乘积的计算次序完全确定,也就是说该连乘积已完全加括号,则可以依此次序反复调用2个矩阵相乘的标准算法计算出矩阵连乘积
3.完全加括号的矩阵连乘积
-
设有四个矩阵 A,B,C,D, 它们的维数分别是:
A=5010 ,B =1040 ,C = 4030 D = 305 -
总共有五中完全加括号的方式,及相应的乘法次数如下
(A((BC)D))------------16000
(A(B(CD))) ------------10500
((AB)(CD))-----------36000
(((AB)C)D) ------------87500
((A(BC))D)--------------34500 -
对于 pXq 矩阵 A 和一个 qXr 矩阵 B, AB 需要 ? 标准乘法计算。
标准乘法次数是:pqr,即:A的行乘以B的行乘以B的列这么多次
理解:用A的一行乘以B的所有列,总共是pr次,但是A有q个行,所以最终是pr*q
//java编写
matrixMultiply(int [][]a,int [][]c, int ra,int ca,int rb,int cb)
{
if (ca!=rb)
Throw new IllegalArgumentException(“矩阵不可乘” );
for(int i=0;i<ra;i++)//ra是矩阵A的行
{
for(int j=0;j<cb;j++)//cb是矩阵B的列
{
int sum=a[i][0]*b[0][j];
for(int k=1;k<rb;k++)//rb是B的行
{
Sum+=a[i][k]*b[k][j];
c[i][j]=sum;
}
}
}
}
- eg:如果 A1, A2, and A3 是 20X100, 100X10, 和 10X50 矩阵,A1XA2XA3乘积运算次数是多少?
4.矩阵连乘问题
-
给定n个矩阵{A1,A2,…,An},其中Ai与Ai+1是可乘的,i=1,2 ,…,n-1。如何确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。
-
穷举法求解思路
穷举法:列举出所有可能的计算次序, 并计算出每一种计算次序相应需要的数乘次数,从中找出一种数乘次数最少的计算次序。
算法复杂度分析:
对于n个矩阵的连乘积,设其不同的计算次序为P(n)。
由于每种加括号方式都可以分解为两个子矩阵的加括号问题:
((A1…Ak)(Ak+1…An))可以得到关于P(n)的递推式如下,k可以取1到n
Catalan 数 P(n) = C(n-1) -
用动态规划思想求解问题?
(1)分析最优解的结构
将矩阵连乘积 AiAi+1…Aj简记为A[i:j] ,这里i≤j。考察计算A[i:j]的最优计算次序。
设这个计算次序在矩阵Ak和Ak+1之间将矩阵链断开, i≤k<j,则其相应完全加括号方式为(AiAi+1…Ak )(Ak+1Ak+2…Aj )
所以:总计算量=A[i:k]的计算量加上A[k+1:j]的计算量,再加上A[i:k]和A[k+1:j]相乘的计算量
(2)分析最优解的子问题结构
特征:计算A[i:j]的最优次序所包含的计算矩阵子链 A[i:k]和A[k+1:j]的次序也是最优的。
但是子问题不独立,适合动态规划算法设计,因为eg:假设计算A[1:4],其可被分解为A[1:2]和A[2:4],但是同时都覆盖了矩阵A[2]
矩阵连乘计算次序问题的最优解包含着其子问题的最优解,这种性质称为最优子结构性质。
(3)建立递推关系
递推关系式是通过最优值来构建的!!不是通过最优解构建的!!
以自底向上的方式计算出最优值到底是干嘛?
子问题规模最小的地方就是底,沿着反的递归方向往上合并的过程,逐个让子问题的规模变大,形成大问题的解,最终合成最终原来的解
(4)建立递归算法
从
(5)实际子问题数目
递归是从上至下的,动态规划问题是从下至上,不断合并子问题
- 动态规划求最优解
public static matrixChain(int [] p,int [][] m,int [][] s)
{
int n=p.length-1;
for (int i=1;i<=n;i++)//首先求解最小子问题的答案,i=j时,后面可以查表获取答案
m[i][i]=0;
//下面是m[i,i+r]的子问题,让i到j之间的距离,逐个从2增加到n
for (int r=2;r<=n;r++)//复杂度为n
{
for(int i=1;i<=n-r+1;i++)//复杂度为n
{
//因为要计算min,所以这里计算了一个参考值
int j=i+r-1;
m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j];
s[i][j]=i;
for (int k=i+1;k<j;k++)//复杂度为k
{
int t=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];//最优的m[i,j]
if (t<m[i][j])
{
m[i][j]=t;
s[i][j]=k;//存储了最优解的解,通过s[i][j]可以反向获取最优解
}
}
}
}
}
来源:CSDN
作者:假如我年少有为不自卑~
链接:https://blog.csdn.net/u011436427/article/details/104187109