矩阵连乘问题
矩阵在实际生活中极为重要,但其中的矩阵间乘法的步骤却非常繁琐,当遇到许多个矩阵连乘时,如何减小计算时的代价尤为关键,动态规划可以有效解决该问题。
问题描述
给定n个矩阵A1,A2……An,且保证Ai能够和Ai+1相乘。由于矩阵乘法满足结合律,可以具有不用的运算顺序,求解使矩阵连乘次数最小的结合律所花费的代价。
分析设计
已知数学矩阵的定理:
- 若矩阵A的列等于矩阵B的行,则A和B是可乘的,表示为A * B。
因此n个矩阵连乘的结果应该为第一个矩阵A1的列,最后一个矩阵An的行组成的矩阵。
问题描述中所说的代价应为:
- 已知矩阵 A ( i , j ) A(i,j) A(i,j)和 B ( j , k ) B(j,k) B(j,k),A和B相乘的代价 = i * j * k;。
知道了上面这些前提条件,我们就可以开始分析如何利用动态规划的思想解决了。
对于一个问题,利用动态规划求解需要我们找出可划分的子问题,对于矩阵连乘来说,子问题很明显:其中部分矩阵的连乘问题。
具体来说就是,若在第k个位置上有最优解,则子问题就变为了Ak两边的矩阵的连乘问题了。
设用二维数组C来记录矩阵连乘的结果,从Ai到Aj的连乘问题的解为
C
(
i
,
j
)
C(i,j)
C(i,j),在第k个位置找到最优解,且
1
≤
i
≤
j
≤
n
1\leq i\leq j\leq n
1≤i≤j≤n,那么
C
(
i
,
j
)
=
m
i
n
[
C
(
i
,
k
)
+
C
(
k
+
1
,
j
)
+
m
i
−
1
∗
m
k
∗
m
j
]
C(i,j)=min[C(i,k)+C(k+1,j)+m_{i-1}*m_k*m_j]
C(i,j)=min[C(i,k)+C(k+1,j)+mi−1∗mk∗mj]
同时当 i = j i=j i=j时, C ( i , j ) = 0 C(i,j)=0 C(i,j)=0。
源代码
#include <iostream>
#include <vector>
#include <algorithm>
using namespace std;
//矩阵连乘
void Dpmatrixmul(vector<int> &m, vector<vector<int> > &c) {
int n = m.size() - 1;
for (int i = 1; i <= n; i++) //初始化
c[i][i] = 0;
for (int s = 1; s <= n - 1; s++) {
for (int i = 1; i <= n - s; i++) {
int j = i + s;
for (int k = i; k < j; k++) {
if (c[i][j] > c[i][k] + c[k + 1][j] + m[i - 1] * m[k] * m[j])
c[i][j] = c[i][k] + c[k + 1][j] + m[i - 1] * m[k] * m[j];
}
}
}
}
int main() {
int n;
cout << "输入矩阵个数:";
cin >> n;
vector<int> matrix(n + 1); //矩阵数组,记录n个矩阵的行和列
vector<vector<int> > c(n + 1, vector<int>(n + 1,INT_MAX)); //代价数组
cout << "输入矩阵信息:";
for (int i = 0; i <= n; i++)
cin >> matrix[i];
Dpmatrixmul(matrix, c);
cout << "解决该矩阵的最小代价为:" << c[1][n] << endl;
system("pause");
return 0;
}
运行结果