/*
Name:
Copyright:
Author:
Date: 27-03-17 08:14
Description: 动态规划——矩阵连乘的问题
《问题的引出》
看下面一个例子,计算三个矩阵连乘{A1,A2,A3};维数分别为10*100 , 100*5 , 5*50
按此顺序计算需要的次数((A1*A2)*A3):10X100X5+10X5X50=7500次
按此顺序计算需要的次数(A1*(A2*A3)):10X5X50+10X100X50=75000次
所以问题是:如何确定运算顺序,可以使计算量达到最小化。
枚举显然不可,如果枚举的话,相当于一个“完全加括号问题”,次数为卡特兰数,卡特兰数指数增长,必然不行。
《建立递归关系》
子问题状态的建模(很关键):令m[i][j]表示第i个矩阵至第j个矩阵这段的最优解。
显然如果i=j,则m[i][j]这段中就一个矩阵,需要计算的次数为0;
如果i>j,则m[i][j]=min{m[i][k]+m[k+1][j]+p[i-1]Xp[k]Xp[j]},其中k,在i与j之间游荡,所以i<=k<j ;
代码实现时需要注意的问题:计算顺序!!!
因为你要保证在计算m[i][j]查找m[i][k]和m[k+1][j]的时候,m[i][k]和m[k+1][j]已经计算出来了。
*/
#include<iostream>
#include<string>
using namespace std;
int matrixChain(int i, int j);//自顶向下,使用备忘录数组的动态规划算法
int matrixChain_2(int n);//自底向上的动态规划算法
void traceback(int i,int j);//根据s[][]记录的各个子段的最优解,将其输出
const int MAX = 100;
//p用来记录矩阵的行列,p[i-1]和p[i]分别记录了矩阵A[i]的行数和列数
//m[i][j]用来记录第i个矩阵至第j个矩阵的最优解
//s[][]用来记录从哪里断开的才可得到该最优解
int p[MAX+1],m[MAX+1][MAX+1],s[MAX+1][MAX+1];
int flag[MAX+1]; //记录A[i]是否已经被输出过
int main(int argc, char **argv)
{
//测试数据可以设为六个矩阵分别为
//A1[30*35],A2[35*15],A3[15*5],A4[5*10],A5[10*20],A6[20*25]
//则p[6]={30,35,15,5,10,20,25}
int n = 6;
int t[MAX+1] = {30,35,15,5,10,20,25};
for (int i=0; i<=n; i++)
p[i] = t[i];
cout << matrixChain(1, n) << endl;
// cout << matrixChain_2(n) << endl;
traceback(1, n);
cout << endl;
system("pause");
return 0;
}
int matrixChain(int i, int j)//自顶向下,使用备忘录数组的动态规划算法
{
if (m[i][j] != 0) //默认为0
return m[i][j];
if (i == j)
return 0;
//先处理k=i的情形
m[i][j] = matrixChain(i+1, j) + p[i-1] * p[i] * p[j]; //matrixChain(i, i)==0,就不写了
s[i][j] = i;
//再处理i<k<j的情形
for (int k=i+1; k<j; k++)
{
int t = matrixChain(i, k) + matrixChain(k+1, j) + p[i-1] * p[k] * p[j];
if (t < m[i][j])
{
m[i][j] = t;
s[i][j] = k;
}
}
return m[i][j];
}
int matrixChain_2(int n)//自底向上的动态规划算法
{
for (int i=1; i<=n; i++)
m[i][i] = 0;
for (int len=2; len<=n; len++)//括号里矩阵的数量(长度)
{
for (int i=1; i<=n-len+1; i++)
{
int j = i + len -1;
//先处理k=i的情形
m[i][j] = m[i][i] + m[i+1][j] + p[i-1]*p[i]*p[j];
s[i][j] = i;
//再处理i<k<j的情形
for (int 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;
}
}
}
}
return m[1][n];
}
void traceback(int i,int j)//根据s[][]记录的各个子段的最优解,将其输出
{
if (i == j)
return ;
cout << "(";
traceback(i, s[i][j]);
if (flag[i] == 0)
{
cout << "A" << i;
flag[i] = 1;
}
traceback(s[i][j]+1, j);
if (flag[j] == 0)
{
cout << "A" << j;
flag[j] = 1;
}
cout << ")";
}
矩阵连乘的问题
最新推荐文章于 2021-01-03 20:24:32 发布