矩阵连乘最优结合 动态规划求解

1.引言  多矩阵连乘

对于一般的矩阵乘法来说,如矩阵A(m,n)与矩阵B(n,p)相乘需要进行的加法次数为m*n*p次乘法。

由于矩阵乘法满足结合律,因此矩阵相乘的结合性,会影响整个计算表达式的乘法执行次数。

如下面的例子,其中A(10,5)、B(5,20)、C(20,3):

    (1) ((AB)C) 执行乘法次数为1300次

    (2) (A(BC)) 执行乘法次数为450次

2.求最优的矩阵结合表达式

(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]。

    M[i,j] = 0;    (i == j,表示一个矩阵,当然不需要乘法运算)

    M[i,j] = min(M[i,k]+M[k+1,j]+pi*pk*pj);   (k在[i,j)之间取值,表示分割点的位置,求最适合的分割点使得乘法次数最少)

  下面是使用动态规划计算6个矩阵连乘的示意图。可以使用自底向上计算,这样矩阵的分割点好计算。如先计算01两个矩阵乘积,在计算02三个矩阵乘积,在计算03四个矩阵乘积:

       01 12 23 34 45

       02 13 24 35

       03 14 25

       04 15

       05

 3.程序实例

程序可以根据给出的多个矩阵的行、列,生成最优结合的相乘表达式。

 1 #include <iostream>
 2 #include <vector>
 3 #include <algorithm>
 4 #include <limits.h>
 5 #include <string>
 6 using namespace std;
 7 ///计算M矩阵
 8 int calculate_M(vector<vector<int> >&num,vector<pair<int,int> > &data,vector<vector<int> > &points){
 9     int len = data.size();
10     for(int span = 1;span<len;span++){  ///间隔距离
11         for(int col=0;col<len-span;col++){  ///操作起始列
12
13             for(int i=col;i<col+span;i++){
14                 int tmp = num[col][i] + num[i+1][col+span] + data[col].first*data[i].second*data[col+span].second;
15                 if(tmp < num[col][col+span]){
16                     points[col][col+span] = i;  ///记录分割点
17                     num[col][col+span] = tmp;   ///记录最少乘法次数
18                 }
19             }
20         }
21     }
22     return 0;
23 }
24
25 ///根据记录的分割点,生成最后的矩阵相乘表达式
26 string make_result(vector<vector<int> > &points,int t1,int t2){
27     if(t1 == t2)
28         return string(1,'A'+t1);
29     int split = points[t1][t2];
30     return "("+make_result(points,t1,split)+"*"+make_result(points,split+1,t2)+")";
31 }
32
33 int main()
34 {
35     vector<pair<int,int>> data; ///保存矩阵的行、列
36     data.push_back(make_pair(10,100));  //A
37     data.push_back(make_pair(100,5));   //B
38     data.push_back(make_pair(5,25));    //C
39     data.push_back(make_pair(25,15));   //D
40     data.push_back(make_pair(15,20));   //E
41
42
43     int len = data.size();
44     vector<vector<int> > num(len,vector<int>(len)); ///定义二维向量,并预先分配空间,记录乘法次数
45     vector<vector<int> > points(len,vector<int>(len)); ///定义二维向量,并预先分配空间,记录分割点
46     for(int i=0;i<len;i++){
47         for(int j=0;j<len;j++){
48             points[i][j] = -1;
49             if(i == j)
50                 num[i][j] = 0;  ///自己和自己相乘,所以为0
51             else
52                 num[i][j] = INT_MAX;    ///否则,记为最大整数值
53         }
54     }
55
56     calculate_M(num,data,points);
57     cout<<make_result(points,0,len-1)<<"\t最少乘法次数为:"<<num[0][len-1]<<endl;
58     return 0;
59 }

View Code

输入矩阵,表示每个矩阵的行、列:

输出最优的结合表达式:

  

时间: 2024-10-29 06:34:42

矩阵连乘最优结合 动态规划求解的相关文章

背包问题 matlab-背包问题Matlab动态规划求解程序报错 求指导 万分感谢!!

问题描述 背包问题Matlab动态规划求解程序报错 求指导 万分感谢!! KnapSack1(v,w,n,W) for w=0 to W V[0,w]=0; %将二维数组第一行赋值全零 for i=1 to n for w=0 to W if w_i<=w V[i,w]=max(V[i-1,w],v_i+V[i-1,w-w_i]) %V[i,w]记录权值至少为w且最大的子集{1,2,...,n} else V[i,w]=V[i-1,w]; Return V[i,W]; end end end e

概率问题,动态规划求解

问题描述 概率问题,动态规划求解 大神们,用动态规划怎么解这道题呀? 问题描述 生成n个∈[a,b]的随机整数,输出它们的和为x的概率. 输入格式 一行输入四个整数依次为n,a,b,x,用空格分隔. 输出格式 输出一行包含一个小数位和为x的概率,小数点后保留四位小数 样例输入 2 1 3 4 样例输出 0.3333 数据规模和约定 对于50%的数据,n≤5. 对于100%的数据,n≤100,b≤100. 解决方案 http://zhidao.baidu.com/link?url=DusTYd_4

物件捆绑 背包问题 动态规划 求解

物件捆绑背包问题:给定N元钱,要购买一些器件.器件有主件和附件之分,也即主件可以单独购买,然而购买附件必须购买对应的主件.下表就是一些主件与附件的例子: 主件 附件 电脑      打印机.扫描仪 书柜 图书 书桌          台灯 工作椅 无   把每件物品规定一个重要度,分为5等:用整数1~5表示,第5等最重要.在花费不超过N元(可以等于N元)的前提下,使每件物品的价格与重要度的乘积的总和最大.设第j件物品的价格为v[j],重要度为p[j],共选中了k件物品,编号依次为j1,j2,--

字符串相似度算法 递归与动态规划求解分析

1.概念 编辑距离,指的是两个字符串之间,由一个转换成另一个所需的最少编辑操作次数.许可的编辑操作包括:(1)将一个字符替换成另一个字符,(2)插入一个字符,(3)删除一个字符. 相似度,等于"编辑距离+1"的倒数. 2.分析 设有字符串a[0...n],b[0...m]. (1)当a[i]=b[j]时,说明这时候不需要编辑操作.编辑距离保持,即f(i,j)=f(i-1,j-1) (2)当a[i]!=b[j]时,可以有三种编辑操作. 其中删除和插入操作,只对一个下标i或者j产生影响.如

第十五章 动态规划——最优二叉搜索树

1.前言: 接着学习动态规划方法,最优二叉查找树问题.二叉查找树参考http://www.cnblogs.com/Anker/archive/2013/01/28/2880581.html.如果在二叉树中查找元素不考虑概率及查找不成功的情况下,可以采用红黑树或者平衡二叉树来搜索,这样可以在O(lgn)时间内完成.而现实生活中,查找的关键字是有一定的概率的,就是说有的关键字可能经常被搜索,而有的很少被搜索,而且搜索的关键字可能不存在,为此需要根据关键字出现的概率构建一个二叉树.比如中文输入法字库中

C语言如何求解哈密尔顿回路的问题,其中原始数据是放在一个临界矩阵的数据结构的

问题描述 C语言如何求解哈密尔顿回路的问题,其中原始数据是放在一个临界矩阵的数据结构的 C语言如何求解哈密尔顿回路的问题,其中原始数据是放在一个临界矩阵的数据结构的 解决方案 http://blog.csdn.net/weiguang_123/article/details/7830047 解决方案二: http://www.doc88.com/p-5314124513046.html 解决方案三: http://blog.csdn.net/sunmenggmail/article/detail

算法-求解矩阵乘法的Coppersmith-Winograd方法详解

问题描述 求解矩阵乘法的Coppersmith-Winograd方法详解 求解矩阵乘法的Coppersmith-Winograd方法详解 有代码也行 谢谢各位大神

动态规划总结

动态规划 终于来到了算法设计思想中最难,也最有趣的这部分,在去年的google笔试中,7道算法设计题有2道动态规划(Dynamic Programming). 看了这么久的算法,这部分也是唯一感觉到了比较难的地方, 从这篇文章开始,将花连续的篇幅来讨论一些动态规划的问题.这包括书上介绍过的计算二项式系数,Warshall算法求传递闭包,Floyd算法求完全最短路径,构造最 有二叉查找树,背包问题和记忆功能.也包括一些其他问题的解题报告(动态规划确实很难,对这一章的内容,我将搜索一些其他类型的问题

五大常用算法——分治法,动态规划,回溯法,分支界限法,贪心算法

分治算法一.基本概念    在计算机科学中,分治法是一种很重要的算法.字面上的解释是"分而治之",就是把一个复杂的问题分成两个或更多的相同或相似的子问题,再把子问题分成更小的子问题--直到最后子问题可以简单的直接求解,原问题的解即子问题的解的合并.这个技巧是很多高效算法的基础,如排序算法(快速排序,归并排序),傅立叶变换(快速傅立叶变换)--     任何一个可以用计算机求解的问题所需的计算时间都与其规模有关.问题的规模越小,越容易直接求解,解题所需的计算时间也越少.例如,对于n个元素