《算法导论》——矩阵链乘法
一、问题抛出
二、何为矩阵链乘法
三、动态规划法解决
(PS:这里通俗一点讲就是对于一个长度为n的矩阵链,找到一个中间位置k对其进行划分,使A1…K乘以Ak+1…N的乘法次数最少,要知道前面的最少次数就需要对前面的子链继续进行划分)
(对p[n+1]、m[i][j]、s[i][j]的解释)
当前矩阵的个数为n,那么p[]={30,35,15,5,10,20,25}
m[i][j]为以第i个矩阵开始第j个矩阵结尾的矩阵链的最少乘法次数
s[i][j]则保存这种方案的分割位置
#include "iostream"
#include "vector"
using namespace std;
void MATRIX_CHAIN_ORDER(int* p, int n, vector<vector<int>>& m, vector<vector<int>>& s)//p为矩阵规模,例如Ai 行为p[i-1],列为p[i],n为链的个数
{
int j = 0;
for (int i = 1; i <= n; i++)//都是从1开始,第一个矩阵,第二个。。。
{
m[i][i] = 0; //矩阵长度为1不需要乘
}
for (int l = 2; l <= n; l++) //计算每种长度链的最优分法
{
for (int i = 1; i <= n - l + 1; i++)//i在长度为l的链中的每种可能位置
{
j = l + i - 1;
m[i][j] = INT_MAX;
for (int k = i; k < j; k++)
{
int 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;
}
}
}
}
}
void PRINT_OPTIMAL_PARENS(vector<vector<int>>& s, int i, int j)
{
if (i == j)
{
cout << "A" << i;
}
else
{
cout << "(";
PRINT_OPTIMAL_PARENS(s, i, s[i][j]);
PRINT_OPTIMAL_PARENS(s,s[i][j]+1,j);
cout << ")";
}
}
void main()
{
int n;//矩阵链的规模
cout << "请输入矩阵链的长度" << endl;
cin >> n;
vector<vector<int>> m(n+1); //vector 构建二维数组
for (int i = 0; i <=n; i++)
m[i].resize(n+1);
vector<vector<int>> s(n+1);
for (int i = 0; i <=n; i++)
s[i].resize(n+1);
cout << "请输入矩阵规模序列" << endl;
int* p = new int[n+1];
for (int i = 0; i <= n; i++)//p的长度比矩阵链长度多1
{
cin >> p[i]; //p为{1,2,3...},p[0]为A1的行,p[1]为A1的列,A2的行
}
MATRIX_CHAIN_ORDER(p,n, m, s);
cout << "最优解决方案" << endl;
PRINT_OPTIMAL_PARENS(s, 1, n);
cout << endl;
cout << "乘法次数" << m[1][n] << endl;
system("pause");
}