动态规划之矩阵连乘讲解
注:当时在学矩阵连乘的时候,在网上发现这篇文章总结的不错,便摘抄了下来,今天与大家共享。同时望原创不要见怪!
动态规划之矩阵连乘
给定n个矩阵{A1,A2,…,An},其中Ai与Ai+1是可乘的,i=1,2,…,n-1。考察这n个矩阵的连乘积A1A2…An。由于矩阵乘法满足结合律,故计算矩阵的连乘积可以有许多不同的计算次序,这种计算次序可以用加括号的方式来确定。若一个矩阵连乘积的计算次序完全确定,则可以依此次序反复调用2个矩阵相乘的标准算法(有改进的方法,这里不考虑)计算出矩阵连乘积。若A是一个p×q矩阵,B是一个q×r矩阵,则计算其乘积C=AB的标准算法中,需要进行pqr次数乘。
矩阵连乘积的计算次序不同,计算量也不同,举例如下:
先考察3个矩阵{A1,A2,A3}连乘,设这三个矩阵的维数分别为10×100,100×5,5×50。若按((A1A2)A3)方式需要的数乘次数为10×100×5+10×5×50=7500,若按(A1(A2A3))方式需要的数乘次数为100×5×50+10×100×50=75000。
下面使用动态规划法找出矩阵连乘积的最优计算次序。
1, 设矩阵连乘积AiAi+1…Aj简记为A[i:j],设最优计算次序在Ak和Ak+1之间断开,则加括号方式为:
((AiAi+1…Ak)(Ak+1…Aj))
则依照这个次序,先计算A[i:k]和A[K+1:j]然后再将计算结果相乘,计算量是:
A[i:k]的计算量加上A[K+1:j]的计算量再加上它们相乘的计算量。
问题的一个关键是:计算A[i:j]的最优次序所包含的两个子过程(计算A[i:k]和A[K+1:j])也是最优次序。
2, 设计算A[i:j]所需的最少数乘次数为m[i][j]。
i=j时为单一矩阵,则m[i][i]=0,
i<j时,设最优计算次序在Ak和Ak+1之间断开,则m[i][j]=m[i][k]+m[k+1][j]+pipk+1pj+1,其中p表示数组的维数,例如A0到A5共6个数组(为了C语言的描述方便,下标从0开始),他们表示如下:
//p[0]:第一个矩阵的行数
//p[1]:第一个矩阵的列数,第二个矩阵的行数
//p[2]:第二个矩阵的列数,第三个矩阵的行数
k此时并未确定,需要从i到j-1遍历以寻找一个最小的m[i][j]。我们把这个最小的k放在s[i][j]。
以下是完整实现代码,以一个具体的例子实现,稍加修改即可通用。
#include <iostream>
using namespace std;
//
//MatrixChain计算m[i][j]所需的最少数乘次数
//并记录断开位置s[i][j]
//
void MatrixChain(int *p,int n,int **m,int **s)
{
for(int i=0;i<n;i++)
m[i][i]=0;//单个矩阵相乘,所需数乘次数为0
//以下两个循环是关键之一,以6个矩阵为例(为描述方便,m[i][j]用ij代替)
//需按照如下次序计算
//01 12 23 34 45
//02 13 24 35
//03 14 25
//04 15
//05
//下面行的计算结果将会直接用到上面的结果。例如要计算14,就会用到12,24;或者13,34等等
for(int r=1;r<n;r++)
{
for(int i=0;i<n-r;i++)
{
int j=i+r;
//首先在i断开,即(Ai*(Ai+1...Aj))
m[i][j]=m[i][i]+m[i+1][j]+p[i]*p[i+1]*p[j+1];
s[i][j]=i;
for(int k=i+1;k<j;k++)
{
//然后在k(从i+1开始遍历到j-1)断开,即((Ai...Ak)*(Ak+1...Aj))
int t=m[i][k]+m[k+1][j]+p[i]*p[k+1]*p[j+1];
if(t<m[i][j])//找到更好的断开方法
{
m[i][j]=t;//记录最少数乘次数
s[i][j]=k;//记录断开位置
}
}
}
}
//如果使用下面注释的循环,则是按照如下次序计算
//01 02 03 04 05
//12 13 14 15
//23 24 25
//34 35
//45
//当要计算时14,会用到12,24,而此时24并没有被计算出来。
/*
for(int i=0;i<n;i++)
{
for( int j=i+1;j<n;j++)
{
m[i][j]=m[i][i]+m[i+1][j]+p[i]*p[i+1]*p[j+1];
s[i][j]=i;
for(int k=i+1;k<j;k++)
{
int t=m[i][k]+m[k+1][j]+p[i]*p[k+1]*p[j+1];
if(t<m[i][j])
{
m[i][j]=t;
s[i][j]=k;
}
}
}
}
*/
}
//
//Traceback打印A[i:j]的加括号方式
//
void Traceback(int i,int j,int **s)
{
//s[i][j]记录了断开的位置,即计算A[i:j]的加括号方式为:
//(A[i:s[i][j]])*(A[s[i][j]+1:j])
if(i==j)return;
Traceback(i,s[i][j],s);//递归打印A[i:s[i][j]]的加括号方式
Traceback(s[i][j]+1,j,s);//递归打印A[s[i][j]+1:j]的加括号方式
//能走到这里说明i等于s[i][j],s[i][j]+1等于j
//也就是说这里其实只剩下两个矩阵,不必再分了
cout<<"A"<<i<<"和A"<<(s[i][j]+1)<<"相乘"<<endl;
}
int _tmain(int argc, _TCHAR* argv[])
{
int n=6;//矩阵的个数
int *p=new int[n+1];
//p[0]:第一个矩阵的行数
//p[1]:第一个矩阵的列数,第二个矩阵的行数
//p[2]:第二个矩阵的列数,第三个矩阵的行数
p[0]=30;
p[1]=35;
p[2]=15;
p[3]=5;
p[4]=10;
p[5]=20;
p[6]=25;
int **m,**s;
m=new int*[n];
for( int i=0;i<n;i++)
m[i]=new int[n];
s=new int*[n];
for(int i=0;i<n;i++)
s[i]=new int[n];
MatrixChain(p,n,m,s);
Traceback(0,n-1,s);
for(int i=0;i<n;i++)
{
delete []m[i];
m[i]=NULL;
delete []s[i];
s[i]=NULL;
}
delete []m;
m=NULL;
delete []s;
s = NULL;
delete []p;
p = NULL;
return 0;
}
打印结果是:
A1和A2相乘
A0和A1相乘
A3和A4相乘
A3和A5相乘
A0和A3相乘
实际上要表达的是如下加括号方式:
((A0(A1A2))((A3A4)A5))
加了括号之后用第一个来代替,例如(A1A2)可看作A1,这个结果的数乘次数是15125。
具体实例见:
NYOJ 460 项链
NYOJ 536 开心的mdd
动态规划之矩阵连乘讲解相关推荐
- 【算法】几个数组拆分题的算法(动态规划,矩阵递归和同余问题)
鸽了几个月,终于更了哈哈哈(确实本人懒癌晚期,往往就不更了) 这个学期虽然算是最鸽的一个学期,不过也有些东西,总共一学期做过的三次数组拆分问题感觉上已经够了一篇很不错的文章,其实就有的时候就懒得更了 ...
- python读取csv某一列存入数组_python 读取.csv文件数据到数组(矩阵)的实例讲解
利用numpy库 (缺点:有缺失值就无法读取) 读: import numpy my_matrix = numpy.loadtxt(open("1.csv","rb&qu ...
- python连乘函数_动态规划之矩阵连乘问题Python实现方法
本文实例讲述了动态规划之矩阵连乘问题Python实现方法.分享给大家供大家参考,具体如下: 给定n个矩阵{A1,A2,-,An},其中Ai与Ai+1是可乘的,i=1,2 ,-,n-1.如何确定计算矩阵 ...
- 动态规划实现矩阵连乘
动态规划实现矩阵连乘积: 用动态规划法解矩阵连乘积的最优计算次序问题. 1.分析最优解结构: 设计求解具体问题的动态规划算法的第一步是刻画该问题的最优解结构特征.首先,为方便起见,将矩阵连乘积 ...
- 动态规划解决矩阵连乘问题
动态规划解决矩阵连乘问题 文章目录 动态规划解决矩阵连乘问题 动态规划 1.要素 2.基本思想 3.适用于解最优化问题步骤 一.矩阵连乘问题 规则 矩阵可乘的条件 计算的次序对计算量的影响 二.动态规 ...
- 动态规划:矩阵链连乘问题
动态规划之矩阵连乘问题 矩阵链乘问题简单而言,便是给定n个矩阵{A1,A2--An},其中Ai与Ai+1是可乘的,考察其连乘时进行计算的最小次数. 在计算过程中,不同的加括号方式对于整个计算量有不一样 ...
- python将list转为矩阵_python list转矩阵的实例讲解
python list转矩阵的实例讲解 如下所示: #list转矩阵,矩阵列合并 x = [[1.2,2.2,1.4],[1.3,2.4,2.1],[1,1,0]] #表示有三个点,第一个点为(1,2 ...
- 【史上最详细】动态规划:矩阵连乘问题(C++实现,含备忘录方法)
动态规划与分治法的异同: 相同点:其基本思想都是将待求解问题分解为若干子问题,先求解子问题,再结合这些子问题的解得到原问题的解. 差异点:与分治法不同的是,适合用动态规划法求解的问题经分解得到的子问题 ...
- 顺时针打印矩阵(编程题讲解)
顺时针打印矩阵 题目描述 题目分析 python代码 使用python矩阵的旋转 矩阵的转置代码 python旋转矩阵解法代码 <剑指offer> 编程题讲解. 题目描述 输入 ...
最新文章
- 树莓派制作“数码显微镜”,了解一下?
- 线性规划——规范型,标准型,基阵、基本解、基本可行解、基变量、非基变量.... 概念梳理
- mysql外键约束查询语句_MySQL数据库 : 查询语句,连接查询及外键约束
- 图形验证码校验php,ThinkPHP实现生成和校验验证码功能
- 随机森林做特征重要性排序和特征选择
- mybatis insert 忽略 联合唯一索引_MySQL实战中,Insert语句的使用心得总结
- 年薪35万的深度学习工程师,正面临数百万的人才缺口
- 卸载nginx php mysql_centos7中配置nginx+php-fpm+swoole+mysql环境教程
- WSPSRV.EXE错误导致ISA中断
- win7程序员御用主题包制作
- 集成hello到OpenDaylight发行版中
- 12-8下午 php语法
- BZOJ1008[HNOI2008] 越狱
- 2022年数学建模国赛--赛后总结
- ubuntu上打开markdown文件
- 宝塔绑定域名访问不了_千字长文教你使用 宝塔面板 快速搭建网站
- 第十一章 AWT编程
- 音频之WAV格式编码解析
- PLC SECS/GEM解决方案,设计与应用
- 不平衡电桥中的星三角变换电流关系