用最少的变量实现矩阵链乘算法的构想及其递归输出结果c++代码

1.问题描述

给定n个矩阵构成的一个链<A1,A2,A3,…An>,其中i=1,2,…n,矩阵A的维数为pi-1pi,对乘积 A1A2…An 以一种最小化标量乘法次数的方式进行加全部括号。
注意:在矩阵链乘问题中,实际上并没有把矩阵相乘,目的是确定一个具有最小代价的矩阵相乘顺序。找出这样一个结合顺序使得相乘的代价最低。

2.问题分析

  1. 最优加全部括号的结构
      动态规划第一步是寻找一个最优的子结构。假设现在要计算AiAi+1…Aj的值,计算Ai…j过程当中肯定会存在某个k值(i<=k<j)将Ai…j分成两部分,使得Ai…j的计算量最小。分成两个子问题Ai…k和Ak+1…j,需要继续递归寻找这两个子问题的最优解。
      有分析可以到最优子结构为:假设AiAi+1…Aj的一个最优加全括号把乘积在Ak和Ak+1之间分开,则Ai…k和Ak+1…j也都是最优加全括号的。
  2. 一个递归解
      设m[i,j]为计算机矩阵Ai…j所需的标量乘法运算次数的最小值,对此计算A1…n的最小代价就是m[1,n]。现在需要来递归定义m[i,j],分两种情况进行讨论如下:
    当i==j时:m[i,j] = 0,(此时只包含一个矩阵)
    当i<j 时:从步骤1中需要寻找一个k(i≤k<j)值,使得m[i,j] =min{m[i,k]+m[k+1,j]+pi-1pkpj} (i≤k<j)。
  3. 计算最优代价
      虽然给出了递归解的过程,但是在实现的时候不采用递归实现,而是借助辅助空间,使用自底向上的表格进行实现。设矩阵Ai的维数为pi-1pi,i=1,2…n。输入序列为:p=<p0,p1,…pn>,length[p] = n+1。使用m[n][n]保存m[i,j]的代价,s[n][n]保存计算m[i,j]时取得最优代价处k的值,最后可以用s中的记录构造一个最优解。书中给出了计算过程的伪代码,摘录如下:
  4. 构造一个最优解
      第三步中已经计算出来最小代价,并保存了相关的记录信息。因此只需对s表格进行递归调用展开既可以得到一个最优解。

3.编程分析

算法程序分为两部分,计算部分和递归输出部分

  • 计算部分
  1. 分析

假设需要计算 i 个矩阵 相乘,则任意两个矩阵之间都需要计算一次代价(自己到自己也需要计算,虽然一定为0),共需要1+2+3+…+i 次,存储到m矩阵(代价矩阵)是一个1到 i的阶梯型,举例当i=5时,m矩阵为

1 2 3 4 5
1 *
2 * *
3 * * *
4 * * * *
5 * * * * *

再来看s矩阵,s矩阵存储的是 i 矩阵乘到 j 矩阵时最优的分割处 k的取值,与m矩阵不同的是,任意两个矩阵之间都需要计算 k值但是自己到自己不需要计算,共需要1+2+3+…+(i-1)次,存储到s矩阵(k值矩阵)是一个1到 i-1的阶梯型,举例当i=5时,s矩阵为

1 2 3 4 5
1
2 *
3 * *
4 * * *
5 * * * *

可以发现s矩阵和m矩阵刚好可以放在同一个 i*i 的矩阵中,这样我们编程的时候就可以只定义一个 i*i 数组,将s矩阵存放在m矩阵对角的位置,循环变量我们准备使用一个矩阵位置 j 和要计算的另一个矩阵到 j 矩阵的距离 n ,减少资源的占用

  1. 代码

预编译部分,定义全局变量

#define Matrix_MUM 8
int min_s,min_k,M[Matrix_MUM][Matrix_MUM]={
   0},p[Matrix_MUM+1]={
   4,5,3,6,4,5,3,6,4};

main() 函数,n 是 i 到 j 相差的矩阵数,用到了 j 和 n 两个变量,i 可以通过 j 和 n 计算出来

int main()
{
   
int j,n;
	for(n=1;n<Matrix_MUM;n++)
		for(j=n;j<Matrix_MUM;j++)
			chain(j,j-n),M[j-n][j]=min_s,M[j][j-n]=min_k;
}

chain() 函数,计算k值

void chain(int j,int i)//计算
{
   
	int s,k;
	for(k
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
矩阵连乘问题是一个经典的动态规划问题,其最优解可以通过建立一个二维数组来求解。具体实现如下: 首先,我们定义一个函数 `matrixChainOrder` 来计算矩阵链乘法的最小代价和最优断点数。该函数的输入参数为一个整数数组 `p`,其中 `p[i]` 表示第 `i` 个矩阵的行数和第 `i+1` 个矩阵的列数。输出参数为一个二维数组 `s`,其中 `s[i][j]` 表示从第 `i` 个矩阵到第 `j` 个矩阵之间的最优断点数。 ```c++ void matrixChainOrder(int p[], int n, int **s) { int m[n][n]; for (int i = 1; i < n; i++) { m[i][i] = 0; } for (int l = 2; l < n; l++) { for (int i = 1; i < n-l+1; i++) { int j = i + l - 1; m[i][j] = INT_MAX; for (int k = i; k <= j-1; 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; } } } } } ``` 在上述函数中,我们首先定义了一个二维数组 `m`,其中 `m[i][j]` 表示从第 `i` 个矩阵到第 `j` 个矩阵之间的最小代价。然后,我们通过两层循环来计算 `m` 数组的值。在内层循环中,我们枚举了所有可能的断点位置 `k`,计算出从第 `i` 个矩阵到第 `k` 个矩阵和从第 `k+1` 个矩阵到第 `j` 个矩阵之间的最小代价,然后加上两个矩阵相乘的代价 `p[i-1]*p[k]*p[j]`,得到从第 `i` 个矩阵到第 `j` 个矩阵之间的总代价 `q`。最后,我们选择代价最小的断点位置 `k`,将其保存到数组 `s` 中。 最后,我们可以通过如下代码输出最优断点数: ```c++ void printOptimalParens(int **s, 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 << ")"; } } ``` 在上述代码中,我们通过归调用 `printOptimalParens` 函数来输出最优断点数。首先,如果 `i` 等于 `j`,那么说明只有一个矩阵,直接输出 `A[i]` 即可。否则,我们在输出左括号后归地输出左子树和右子树,最后再输出右括号。其中,左子树的范围是从第 `i` 个矩阵到第 `s[i][j]` 个矩阵,右子树的范围是从第 `s[i][j]+1` 个矩阵到第 `j` 个矩阵。 完整代码如下:

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值