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

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 }

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

输出最优的结合表达式:

  

时间: 2024-10-14 06:52:54

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

1008-----算法笔记----------0-1背包问题(动态规划求解)

1.问题描述 给定n种物品和一个背包,物品i的重量是wi,其价值为vi,背包的容量为C.问:应该如何选择装入背包的物品,使得装入背包中物品的总价值最大? 2.问题分析 上述问题可以抽象为一个整数规划问题,即求满足 (a)Σwixi ≤ C:(b)xi ∈(0,1),  1≤i≤n:条件下,∑vixi最大时的一个物品xi序列.分析问题可以发现,该问题具有最优子结构性质,那么就可以尝试用动态规划方法求解,而动态规划求解的关键就是列出问题的递归关系表达式. 设m(i,j)为背包容量为j,可选物品为i,

动态规划求解所有字符的组合数

一,问题描述 给定若干个字符,求解 这些字符能够表示的最多组合个数.比如{'a','b','c'} 一共有七种组合.(每种组合没有重复的字符 且 组合的种数与顺序无关,如 ab 和 ba 是同一种组合) a.b .c .ab .ac .bc .abc 其实,求组合个数,可以用公式来求解:具给定 n种字符,一共有  c(n,1)+c(n,2)+...+c(n,n)种不同的组合.其中,c(n,i)表示:从n个字符中任选 i 个的组合数,数学表示为:C in. 二,DP算法思路 既然已经可以用上面的公

【算法导论之七】动态规划求解最长公共子序列

一.动态规划的概念 动态规划(Dynamic Programming)是通过组合子问题的解而解决整个问题的.分治算法是指将问题划分成一些独立的子问题,递归地求解各子问题,然后合并子问题的解而得到原始问题的解,与此不同,动态规划适用于子问题不是独立的情况,也就是各个子问题包含公共的子问题.在这种情况下,采用分治法会做许多不必要的工作,即重复地求解公共地子问题.动态规划算法对每个子问题只求解一次,将其结果保存在一张表中,从而避免每次遇到各个子问题时重新计算答案. 动态规划通常应用于最优化问题.此类问

动态规划求解最长公共子序列

动态规划算法与分治法类似,其基本思想也是将待求解问题分解成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解.与分治法不同的是,适合于用动态规划求解的问题,经分解得到的子问题往往不是互相独立的.若用分治法来解决这类问题,则分解得到的子问题数目太多,以至于最后解决原问题需要耗费指数时间.然而,不同子问题的数目常常只有多项式量级.在用分治法求解时,有些子问题被重复计算了许多次.如果我们能够保存已解决的子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,从而得到多项式

动态规划求解最大字段和及其变种问题

动态规划(Dynamic Programming, DP)为一常用算法思想,本文讲述如何利用DP解决常见的最大字段和及其变种问题. 一. 最大字段和问题 问题定义 设数组为a[k],1≤k≤n,最大字段和X定义为: X=max1≤i≤j≤n{∑k=ija[k]} X直观含义即,求任一连续字数组的最大和. 问题分析 不妨设: b[j]=max1≤m≤j{∑k=mja[k]} 其中,1≤j≤n b[j]的直观含义为,以a[j]为结束元素的连续数组的最大和. 由X和b[j]的定义,易知: X=max1

动态规划求解0-1背包问题

0-1背包问题是: 一个背包能承受的最大容量为max_weight,  现在有n个物品, 它们的重量分别是{w1,w2,w3,......wn}, 和价值分别是{v1,v2,......vn}, 现在要求在满足背包装载的物品不超过最大容量的前提下,保证装载的物品的价值最大? 动态规划求解过程可以这样理解: 对于前i件物品,背包剩余容量为j时,所取得的最大价值(此时称为状态3)只依赖于两个状态. 状态1:前i-1件物品,背包剩余容量为j.在该状态下,只要不选第i个物品,就可以转换到状态3. 状态2

动态规划求解矩阵连乘问题Java实现

首先我们来看看动态规划的四个步骤: 1. 找出最优解的性质,并且刻画其结构特性: 2. 递归的定义最优解: 3. 以自底向上的方式刻画最优值: 4. 根据计算最优值时候得到的信息,构造最优解 其中改进的动态规划算法:备忘录法,是以自顶向下的方式刻画最优值,对于动态规划方法和备忘录方法,两者的使用情况如下: 一般来讲,当一个问题的所有子问题都至少要解一次时,使用动态规划算法比使用备忘录方法好.此时,动态规划算法没有任何多余的计算.同时,对于许多问题,常常可以利用其规则的表格存取方式,减少动态规划算

《算法导论》读书笔记之第16章 0-1背包问题—动态规划求解

原文:http://www.cnblogs.com/Anker/archive/2013/05/04/3059070.html 1.前言 前段时间忙着搞毕业论文,看书效率不高,导致博客一个多月没有更新了.前段时间真是有些堕落啊,混日子的感觉,很少不爽.今天开始继续看算法导论.今天继续学习动态规划和贪心算法.首先简单的介绍一下动态规划与贪心算法的各自特点及其区别.然后针对0-1背包问题进行讨论.最后给出一个简单的测试例子,联系动态规划实现0-1背包问题. 2.动态规划与贪心算法 关于动态规划的总结

动态规划求解最长递增子序列的长度

一,问题描述 给定一个序列,求解它的最长 递增 子序列 的长度.比如: arr[] = {3,1,4,1,5,9,2,6,5}   的最长递增子序列长度为4.即为:1,4,5,9 二,算法分析 有两种方式来求解,一种是转化为LCS问题.即,首先对数组排序,将排序后的结果存储在辅助数组中.排序时间复杂度O(NlogN),排序后的数组与原数组组成了LCS(N,N)问题.解决LCS问题的时间复杂度为O(N^2),故整个算法的时间复杂度为O(N^2),空间复杂度为O(N) 另一种方式是直接用DP求解,算