给定一个n个矩阵的序列〈A1,A2,A3...An〉
,我们要计算他们的乘积:A1A2A3...An,由于矩阵乘法满足结合律,加括号不会影响结果,但是不同的加括号方法,算法复杂度有很大的差别:
考虑矩阵链:〈A1,A2,A3〉,三个矩阵规模分别为10×100、100×5、5×50
如果按((A1A2)A3)方式,需要做10∗100∗5=5000次,再与A3相乘,又需要10∗5∗50=2500,共需要7500次运算:
如果按(A1(A2A3))方式计算,共需要100∗5∗50+10∗100∗50=75000次标量乘法,具有10倍的差别。可见一个好的加括号方式,对计算效率有很大影响。
为了得到所需乘法次数最少的方案,需要计算所有种方案的代价。
对一个n个矩阵的链,令P(n) 表示可供选择的括号化方案的数量。
完全括号化方案的矩阵乘积可以描述为两个完全括号化的部分相乘的形式,
P(n)=1 , n=1
P(n)=∑n−1k=1P(k)P(n−k), n≥2
k为分割点,即第k个矩阵和第k+1个矩阵之间可以看出括号化方案的数量与n呈指数关系Ω(2n),
若采用暴力搜索比较所有括号化方案的代价,效率很差!
由于要求得矩阵链〈Ai,Ai+1,Ai+2...Aj〉
的最优括号化方案,我们可以将问题划分为两个子问题〈Ai,Ai+1...Ak〉和〈Ak+1,Ak+2...Aj〉的最优括号化方案的组合,这也是可以采用动态规划的一个重要标示。即一个大的问题的解是其子问题的组合。我们需要遍历所有的k值i≤k≤j−1
即考查所用的划分点。
令m[i,j],i≤j
标示矩阵链〈Ai,Ai+1,Ai+2...Aj〉的最优括号化方案所需乘法次数的最小值。 递归算法会多次遇到同一个子问题,与钢铁切割很类似,每一次高层的运算,都会调用底层结果,越是底层,被调用的次数越多。所以可以采用自底向上的方法,先对底层逐个求解,当上层需要调用底层时,底层已经被求解完毕。 长度为j-i+1的最优计算代价q。 上文来源:https://blog.csdn.net/luoshixian099/article/details/46344175 矩阵链〈Ai,Ai+1,Ai+2...Aj〉 ,由于二维矩阵s[i][j]记录了对应划分位置k,指出了应该在Ak和Ak+1之间,同样在矩阵链\left[中最优划分位置一定保存在数组s[i][s[i,j]]内,矩阵;链〈Ak+1,Ak+2...Aj〉的最优划分位置一定保存在s[s[i][j]+1]][j]数组内,可以不断递归出最优解。 计算下列矩阵最优链乘 矩阵输入初始化为p[] = {30,35,15,5,10,20,25} 今天没时间了,就注释分析吧 示例代码: 输出分析: 输出的表格从左上角作为(1,1),以直角坐标系的方式读,(i,j)表示从矩阵Ai到矩阵Aj的最优代价。 算法小白,有不对的地方,请大佬指出,谢谢!
当i=j时,m[i,j]=0,只有一个矩阵不涉及乘法运算
当i
m[i,j]=0,(i=j)
m[i,j]=min{m[i,k]+m[k+1,j]+pi−1pkpj},i3.计算最优代价
用m[i][j]二维矩阵保存对应链〈Ai,Ai+1,Ai+2...Aj〉
用s[i][j]二维矩阵保存对应链〈Ai,Ai+1,Ai+2...Aj〉长度为j-i+1的最优划分位置k。// c语言函数实现
void Matrix_Chain_Order(int p[],int n)
{
int i,j,L,k,q;
for(i=1;i<=n;i++)//先对单个矩阵的链,求解,即所有m[i][i] =0;
{
m[i][i]=0;
}
for(L=2;L<=n;L++) //L 表示i,j间长度,即矩阵链的长度,在n允许的范围内逐渐增加L
for(i=1;i<=n-L+1;i++) //在给定p[]中的矩阵链中,对所有种长度为L的情况计算
{
j = i+L-1;
m[i][j]=-1;
for(k=i;k<=j-1;k++)
{
q = m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];//计算划分的代价,并将最有代价和位置分别存在m[i][j]和s[i][j]中 if(q
构造最优解
示例:
矩阵
A1
A2
A3
A4
A5
A6
规模
30*35
35*15
15*5
5*10
10*20
20*25
分析:
#include