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=i;k<j;k++){s=M[i][k]+M[k+1][j]+p[i]*p[k+1]*p[j+1];if(k==i)min_s=s,min_k=k;if(s<min_s)min_s=s,min_k=k;}
}
  • 输出部分
  1. 分析
    当 m矩阵和s矩阵计算完成后,我们就可以知道任意两个矩阵之间的最优计算方式,例如要找出 i 到 j 之间的最优计算方式,就需要在 s 矩阵中找出 i 到 j 的 k值作为分割点,将其分为两个部分,i 到 k 和k+1 到 j,之后继续在s矩阵分别中找到这两部分的分割点一直分割,直到 i 和 j 相等或者相邻(相差1)
    我们发现这像极了递归的手法,于是我们决定在程序最不重要的输出结果部分采用做作的递归方式,把上一步节省的资源充分利用起来
  2. 代码

*c() 函数,递归输出,当i和j相等或者相差1的时候结束,否则根据 k值分割继续递归

char *c(int i,int j)//结果{char s[80],t[80];if(i==j){s[0]='A';s[1]='0'+i;s[2]=0;return &s[0];}if(j-i==1){s[0]='A';s[1]='0'+i;s[2]=0;t[0]='A';t[1]='0'+j;t[2]=0;return kh(s,t);}strcpy(s,c(i,M[j][i]));strcpy(t,c(M[j][i]+1,j));return kh(s,t);
}

kh() 函数,给字符串前后加上括号

char *kh(char *str1,char *str2)//括号
{char str[80]="(";strcat(str,str1);strcat(str,str2);strcat(str,")");return &str[0];
}

4.完整代码

#include<stdio.h>
#include<iostream>
#include<string.h>
using namespace std;
#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};int main()
{char s[80];char *c(int,int);void chain(int j,int i);void printmatrix();int j,n;//n:j-i ji之间相差几个矩阵for(n=1;n<Matrix_MUM;n++)for(j=n;j<Matrix_MUM;j++)//i=j-nchain(j,j-n),M[j-n][j]=min_s,M[j][j-n]=min_k;//s矩阵存在对称位置printmatrix();strcpy(s,c(0,6));puts(s);getchar();return 0;
}
void chain(int j,int i)//计算
{int s,k;for(k=i;k<j;k++){s=M[i][k]+M[k+1][j]+p[i]*p[k+1]*p[j+1];if(k==i)min_s=s,min_k=k;if(s<min_s)min_s=s,min_k=k;}
}void printmatrix()//输出
{int i,j;cout<<"输出m矩阵"<<endl;for(j=0;j<Matrix_MUM;j++){for(i=0;i<=j;i++)cout<<M[i][j]<<"  ";cout<<endl;}cout<<endl<<"输出s矩阵";for(j=0;j<Matrix_MUM;j++){for(i=0;i<=j-1;i++)cout<<M[j][i]+1<<"  ";cout<<endl;}
}
char *kh(char *str1,char *str2)//括号
{char str[80]="(";strcat(str,str1);strcat(str,str2);strcat(str,")");return &str[0];
}
char *c(int i,int j)//结果{char s[80],t[80];if(i==j){s[0]='A';s[1]='0'+i;s[2]=0;return &s[0];}if(j-i==1){s[0]='A';s[1]='0'+i;s[2]=0;t[0]='A';t[1]='0'+j;t[2]=0;return kh(s,t);}strcpy(s,c(i,M[j][i]));strcpy(t,c(M[j][i]+1,j));return kh(s,t);
}

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

  1. 矩阵相乘的strassen算法_矩阵乘法的Strassen算法+动态规划算法(矩阵链相乘和硬币问题)...

    矩阵乘法的Strassen 这个算法就是在矩阵乘法中采用分治法,能够有效的提高算法的效率. 先来看看咱们在高等代数中学的普通矩阵的乘法 两个矩阵相乘 上边这种普通求解方法的复杂度为: O(n3) 也称 ...

  2. 【动态规划】区间DP - 最优矩阵链乘(另附POJ1651Multiplication Puzzle)

    最优矩阵链乘(动态规划) 一个n∗mn*mn∗m的矩阵由 nnn 行 mmm 列共 n∗mn*mn∗m 排列而成.两个矩阵A和B可以相乘当且仅当A的列数等于B的行数.一个nm的矩阵乘mp的矩阵,运算量 ...

  3. 【动态规划】矩阵链相乘 (ssl 1596)/能量项链 (ssl 2006)

    矩阵链相乘{\color{Cyan} 矩阵链相乘 }矩阵链相乘 Description Input n表示矩阵的个数(<=100) n+1个数,表示矩阵(<=100) Output 最小的 ...

  4. 以空间换时间——动态规划算法及其应用:矩阵链相乘

    动态规划算法是5大算法基础中最重要的一个,它专门用来解决平面世界下的应用,即会多次使用二维数组. 当然动态规划算法是空间换时间的算法,也就是说:我们可以利用空间资源来使某算法问题的时间复杂度降到最低. ...

  5. 【动态规划】矩阵链乘法

    矩阵链乘法    求解矩阵链相乘问题时动态规划算法的另一个例子.给定一个n个矩阵的序列(矩阵链)<A1,A2,...,An>,我们希望计算它们的乘积  A1A2...An    为了计算表 ...

  6. 15.2 矩阵链乘法

    1.代码 public class MatrixChainMultiplication {public static void main(String[] args) { // 在该代码中,我们首先创 ...

  7. 矩阵链乘法问题 (算法)

    一.概述 以两个矩阵相乘为例,A1*A2,A1和A2为两个矩阵,假设A1的行列数是p*q,A2的行列数是q*r.注意这里由于是A1乘以A2,所以A1的列数要等于A2的行数,否则无法做矩阵乘法,满足上述 ...

  8. 动态规划典型题之——矩阵链乘法

    动态规划是算法分析与设计中一种重要的算法.其核心思想是将大问题划分为小问题进行解决,从而一步步获取最优解的处理算法. 文章目录 一.矩阵链相乘问题 二.求解 1.构建备忘录 2.回溯 结果展示 一.矩 ...

  9. 动态规划——矩阵链相乘

    如果看过我上一篇文章(动态规划--最长公共子序列)的同学,相信已经对动态规划的思想有了一定的了解和认识,即把之前求解得出的子问题存储起来,以便后续求解大问题直接使用. 本章要讲解的问题是矩阵链相乘.因 ...

最新文章

  1. Spring Boot骚操作-多数据源Service层封装
  2. 聚类之K-means均值聚类
  3. GNN笔记: random walk
  4. 关于armv7指令集的一个直观数据
  5. 工作145:vue里面取消console和debugger
  6. 小米MIXAlpha将首发1亿像素传感器:1/1.33英寸大底业内无敌
  7. 如何在linux mysql_如何在linux下安装mysql
  8. promise 为什么出现
  9. 《Javascript高级程序设计》读书笔记(1-3章)
  10. OFFICE技术讲座:由-(减号)的绘制差异,看不同字体引擎的处理
  11. SocksCap64
  12. [境内法规]中国人民银行关于印发《反洗钱现场检查管理办法(试行)》的通知—银发〔2007〕175号
  13. 10个比较有用的jQuery插件
  14. 伦斯勒理工学院计算机科学专业强吗,伦斯勒理工学院专业排名一览及最强专业推荐(USNEWS美国大学排名)...
  15. 苏世民:顶尖领导者的52条法则
  16. ccf除法-线段树模板
  17. mysql保存微信昵称特殊字符
  18. 【华为OD机试真题】促销活动(货币兑换)100%通过率
  19. CSAPP:Attack Lab —— 缓冲区溢出攻击实验
  20. ASP.NET中 RadioButtonList(单选按钮组)的使用

热门文章

  1. CNCF中国云原生调查报告
  2. vue-cli+webpack 的项目中怎么导入bootstrap与jquery
  3. 根据爬虫实现语义泛化的拓展思路
  4. Centos7解除自动锁屏及修改主机名
  5. 用LAMP架构搭建自己的博客
  6. Linux下,支付宝安全控件失效,解决方法
  7. 三轴陀螺仪与加速度计如何辅助Iphone定位的
  8. linux sudo 权限_在Linux中使用sudo委派权限
  9. leetcode中等之1709.访问日期之间最大的空档期
  10. 使用Python请求http/https时设置失败重试次数