动态规划:矩阵连乘问题
2017-04-11 15:09
267 查看
问题描述
给定n个矩阵{A1,A2,A3,⋯,An}, 其中Ai与Ai+1是可乘的, i = 1, 2, ⋯ , n-1.考察这n个矩阵的连乘积A1A2,⋯,An.由于矩阵乘法满足结合律,所以计算矩阵的连乘积可有多种不同的计算次序,而不同的计算次序有不同的计算量。设计算法求得多个矩阵连乘时的最小计算量。解决方案
分析最优解的性质 (thinking top-dwon)为方便起见,将矩阵连乘积AiAi+1⋯Aj简记为A[i:j]。考察计算A[1:n]的最优计算次序。设这个计算次序在矩阵Ak和Ak+1之间将矩阵链断开, 1 <= k < n, 则其相应的完全加括号方式为((A1⋯AK)(Ak+1⋯An))。依此次序,先计算A[1:k]和A[k+1:n],然后将计算结果相乘得到A[1:n],依此计算顺序总计算量为A[1:k]的计算量加上A[k+1:n]的计算量,再加上A[1:k]和A[k+1:n]相乘的计算量。
关键特征:计算A[1:n]的最优次序所包含的计算矩阵子链A[1:k]和A[k+1:n]的次序也是最优的。即满足最优子结构性质。
建立递归关系
对于矩阵连乘积的最优计算次序问题,设计算A[i:j],1<=i<=j<=n,所需的最少数乘次数为m[i][j],则原问题的最优值为m[1]
。可以将m[i][j]递归的定义为
m[i][j]={0min{m[i][k]+m[k+1][j]+Pi−1PkPj}i = ji < j且i<=k<j
m[i][j]给出了最优值,即计算A[i:j]所需最少数乘次数。同时还确定了计算A[i:j]的最优次序中的断开位置k,也就是说,对于这个k有
m[i][j]=m[i][k]+m[k+1][j]+Pi−1PkPj
若将对应于m[i][j]的断开位置k记为s[i][j],在计算出最优值m[i][j]后,可递归地由s[i][j]构造出相应的最优解。
计算最优值(solving bottom-up)
由于该问题满足子问题重叠的性质,如果采用递归方式求解,将大量重复计算,因此需要自底向上进行求解。在计算过程中,保存已解决的子问题答案。每个子问题只计算一次,而在后面需要时只要简单查一下,从而避免大量重复计算,最终得到多项式时间的算法。用数组p表示矩阵的维数,用二维数组m来保存最优解,用二维数组s记录最优断开位置k。
构造最优解
上面给出了计算最优解的递推式,可以通过查表m[1]
即可得到最优值。如果需要构造最优解,需要利用二维数组s中保存的信息,即矩阵链断开的位置。具体算法在下面的Traceback函数中给出。
实现代码
/* **动态规划——矩阵连乘 */ #include <stdio.h> #include <stdlib.h> #define n 7 void MartixChain(int p[], int m[] , int s[] ); void Traceback(int i, int j, int s[] ); int main() { int p = {30, 35, 15, 5, 10, 20, 25}; int m ; int s ; MartixChain(p, m, s); Traceback(1, 6, s); return 0; } void MartixChain(int p[], int m[] , int s[] ) { //计算最优值 int i, r, j, k; for (i = 1; i <= n - 1; i++) m[i][i] = 0; for (r = 2; r <= n - 1; r++) { for (i = 1; i <= n - r; i++) { j = i + r - 1; m[i][j] = m[i + 1][j] + p[i - 1] * p[i] * p[j]; //k=i s[i][j] = i; for (k = i + 1; k < j; k++) { //找出最小值 int t = m[i][k] + m[k + 1][j] + p[i - 1] * p[k] * p[j]; if (t < m[i][j]) { m[i][j] = t; s[i][j] = k; } } } } } void Traceback(int i, int j, int s[] ) { //构造最优解 if (i == j) return; Traceback(i, s[i][j], s); Traceback(s[i][j] + 1, j, s); printf("Multiply A %d, %d", i, s[i][j]); printf("and A %d, %d\n", s[i][j] + 1, j); }
相关文章推荐