给出一个矩阵链,A1A2...An。求最小的相乘运算次数。
如:n*k 的 Ai 和 k*m 的A(i+1),则相乘运算次数为n*k*m。
如:n*k 的 Ai 和 k*m 的A(i+1),则相乘运算次数为n*k*m。
给AiA(i+1)...A加括号(1≤i≤j≤n),求最小代价,用m[i][j]来记录Ai...Aj最小的矩阵乘法运算次数,那么A1...An的最优解就是m[1][n]。
当只有一个矩阵时,m[i][i] = 0 (i = 1,2...,n);
当多个矩阵时,即 i<j,通过加括号来构造子结构。在Ak处把一个矩阵链划分成两个链,即Ai...Aj划分成Ai...Ak, A(k+1)...Aj(i≤k<j)。Ai...kA(k+1)...j的乘法运算次数就是p[i-1]p[k]p[j],所以得到m[i][j] = m[i][k] + m[k+1][j] + p[i-1]p[k]p[j];
递归方程如下:
m[i][j] = 0, i = j;
m[i][j] = min(i≤k<j){m[i][k] + m[k+1][j] + p[i-1]p[k]p[j]}, i < j.
/**
* @brief 求最优矩阵链乘
* @param p 一个序列, Ai 为 p[i-1] * p[i] 的矩阵
* @param pLength 序列长度
* @param m m[i][j]记录Ai...Aj最小乘法运算次数
* @param s s[i][j]记录Ai...Aj最小乘法运算次数时k值
*/
void MatricChainOrder(int p[], int pLength, int m[][MAXN+10], int s[][MAXN+10])
{
int n = pLength - 1, chainLen, i, j, k, q;
for (i = 1; i <= n; i++)
{
m[i][i] = 0;
}
for (chainLen = 2; chainLen <= n; chainLen++)
{
for (i = 1; i <= n - chainLen + 1; i++)
{
j = i + chainLen - 1;
m[i][j] = INT_MAX;
for (k = i; k <= j - 1; k++)
{
q = m[i][k] + m[k + 1][j] + p[i - 1] * p[k] * p[j];
if (q < m[i][j])
{
m[i][j] = q;
s[i][j] = k;
}
}
}
}
}
/**
* @brief 打印加括号的方案
*/
void PrintOptimalParens(int s[][MAXN+10], int i, int j)
{
if (i == j)
{
cout << "A" << i;
}
else
{
cout << "(";
PrintOptimalParens(s, i, s[i][j]);
PrintOptimalParens(s, s[i][j] + 1, j);
cout << ")";
}
}