动态规划法解矩阵连乘问题

合集下载
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

动态规划法解矩阵连乘问题

实验内容

给定n个矩阵{A1,A2,….An},其中Ai与Ai+1是可乘的,i=1,2,3。。。,n-1。我们要计算这n个矩阵的连乘积。由于矩阵乘法满足结合性,故计算矩阵连乘积可以有许多不同的计算次序。这种计算次序可以用加括号的方式确定。若一个矩阵连乘积的计算次序完全确定,也就是说该连乘积已完全加括号,则我们可依此次序反复调用2个矩阵相乘的标准算法计算出矩阵连乘积。

解题思路

将矩阵连乘积A(i)A(i+1)…A(j)简记为A[i:j],这里 i <= j。考察计算A[i:j]的最优计算次序。设这个计算次序在矩阵A(k)和A(k+1)之间将矩阵链断开,i <= k < j, 则其相应完全加括号方式为(A(i)A(i+1)…A(k)) * (A(k+1)A(k+2)…A(j))。

特征:计算A[i:j]的最优次序所包含的计算矩阵子链 A[i:k]和A[k+1:j]的次序也是最优的。

矩阵连乘计算次序问题的最优解包含着其子问题的最优解。

设计算A[i:j],1 <= i <= j <= n,所需要的最少数乘次数m[i,j],则原问题的最优值为m[1,n]

当i = j时,A[i:j]=Ai,因此,m[i,i] = 0,i = 1,2,…,n

当i < j时,m[i,j] = m[i,k] + m[k+1,j] + p(i-1)p(k)p(j)这里A(i)的维数为

p(i-1)*(i)(注:p(i-1)为矩阵A(i)的行数,p(i)为矩阵A[i]的列数)

实验

实验代码

#include

#include

using namespace std ;

class matrix_chain

{

public:

matrix_chain(const vector & c) {

cols = c ;

count = cols.size () ;

mc.resize (count) ;

s.resize (count) ;

for (int i = 0; i < count; ++i) {

mc[i].resize (count) ;

s[i].resize (count) ;

}

for (i = 0; i < count; ++i) {

for (int j = 0; j < count; ++j) {

mc[i][j] = 0 ;

s[i][j] = 0 ;

}

}

}

// 记录每次子问题的结果

void lookup_chain () {

__lookup_chain (1, count - 1) ;

min_count = mc[1][count - 1] ;

cout << "min_multi_count = "<< min_count << endl ;

// 输出最优计算次序

__trackback (1, count - 1) ;

}

// 使用普通方法进行计算

void calculate () {

int n = count - 1; // 矩阵的个数

// r 表示每次宽度

// i,j表示从从矩阵i到矩阵j

// k 表示切割位置

for (int r = 2; r <= n; ++ r) {

for (int i = 1; i <= n - r + 1; ++ i) {

int j = i + r - 1 ;

// 从矩阵i到矩阵j连乘,从i的位置切割,前半部分为0

mc[i][j] = mc[i+1][j] + cols[i-1] * cols[i] * cols[j] ;

s[i][j] = i ;

for (int k = i + 1; k < j; ++ k) {

int temp = mc[i][k] + mc[k + 1][j] +

cols[i-1] * cols[k] * cols[j] ;

if (temp < mc[i][j]) {

mc[i][j] = temp ;

s[i][j] = k ;

}

} // for k

} // for i

} // for r

min_count = mc[1][n] ;

cout << "min_multi_count = "<< min_count << endl ;

// 输出最优计算次序

__trackback (1, n) ;

}

private:

int __lookup_chain (int i, int j) {

// 该最优解已求出,直接返回

if (mc[i][j] > 0) {

return mc[i][j] ;

}

if (i == j) {

return 0 ; // 不需要计算,直接返回

}

// 下面两行计算从i到j按照顺序计算的情况

int u = __lookup_chain (i, i) + __lookup_chain (i + 1, j)

+ cols[i-1] * cols[i] * cols[j] ;

s[i][j] = i ;

for (int k = i + 1; k < j; ++ k) {

int temp = __lookup_chain(i, k) + __lookup_chain(k + 1, j)

+ cols[i - 1] * cols[k] * cols[j] ;

if (temp < u) {

u = temp ;

s[i][j] = k ;

}

}

mc[i][j] = u ;

return u ;

}

void __trackback (int i, int j) {

if (i == j) {

return ;

}

__trackback (i, s[i][j]) ;

__trackback (s[i][j] + 1, j) ;

cout <

}

private:

vector cols ; // 列数

int count ; // 矩阵个数+ 1

vector > mc; // 从第i个矩阵乘到第j个矩阵最小数乘次数vector > s; // 最小数乘的切分位置

int min_count ; // 最小数乘次数

} ;

int main()

{

// 初始化

const int MATRIX_COUNT = 6 ;