矩阵连乘最佳加括号方式-动态规划算法

 

一、问题描述

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

        (1)单个矩阵是完全加括号的;

        (2)矩阵连乘积A是完全加括号的,则A可表示为2个完全加括号的矩阵连乘积B和C的乘积并加括号,即A=(BC)。

        例如,矩阵连乘积A1A2A3A4有5种不同的完全加括号的方式:(A1(A2(A3A4))),(A1((A2A3)A4)),((A1A2)(A3A4)),((A1(A2A3))A4),(((A1A2)A3)A4)。每一种完全加括号的方式对应于一个矩阵连乘积的计算次序,这决定着作乘积所需要的计算量。若A是一个p×q矩阵,B是一个q×r矩阵,则计算其乘积C=AB的标准算法中,需要进行pqr次数乘。

        为了说明在计算矩阵连乘积时,加括号方式对整个计算量的影响,先考察3个矩阵{A1,A2,A3}连乘的情况。设这三个矩阵的维数分别为10×100,100×5,5×50。加括号的方式只有两种:((A1A2)A3),(A1(A2A3)),第一种方式需要的数乘次数为10×100×5+10×5×50=7500,第二种方式需要的数乘次数为100×5×50+10×100×50=75000。第二种加括号方式的计算量时第一种方式计算量的10倍。由此可见,在计算矩阵连乘积时,加括号方式,即计算次序对计算量有很大的影响。于是,自然提出矩阵连乘积的最优计算次序问题,即对于给定的相继n个矩阵{A1,A2,…,An}(其中矩阵Ai的维数为pi-1×pi,i=1,2,…,n),如何确定计算矩阵连乘积A1A2…An的计算次序(完全加括号方式),使得依此次序计算矩阵连乘积需要的数乘次数最少。

        穷举搜索法的计算量太大,它不是一个有效的算法,本实验采用动态规划算法解矩阵连乘积的最优计算次序问题。

二、算法思路

         动态规划算法的基本思想是将待求解问题分成若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,动态规划法经分解得到的子问题往往不是相互独立的,前一子问题的解为后一子问题的解提供有用的信息,可以用一个表来记录所有已解决的子问题的答案,不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。

        本实验的算法思路是:

        1、计算最优值算法MatrixChain():建立两张表(即程序中的**m和**s,利用二维指针存放),一张表存储矩阵相乘的最小运算量,主对角线上的值为0,依次求2个矩阵、3个矩阵…、直到n个矩阵相乘的最小运算量,其中每次矩阵相乘的最小运算量都在上一次矩阵相乘的最小运算量的基础上求得,最后一次求得的值即为n个矩阵相乘的最小运算量;另一张表存储最优断开位置。

        2、输出矩阵结合方式算法Traceback():矩阵结合即是给矩阵加括号,打印出矩阵结合方式,由递归过程Traceback()完成。分三种情况:

        (1)只有一个矩阵,则只需打印出A1

        (2)有两个矩阵,则需打印出(A1A2);

        (3)对于矩阵数目大于2,则应该调用递归过程Traceback()两次,构造出最优加括号方式。
 

三、实验源程序

         建立一个矩阵的类Matrix。

         Matrix.h代码

None.gif #ifndef MATRIX_H
None.gif
#define MATRIX_H

None.gif
None.gif
class  Matrix
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
{
InBlock.gif
public
:
InBlock.gif    Matrix();         
//构造函数

InBlock.gif
    ~Matrix();        //析构函数
InBlock.gif
    bool Run();       //运行接口函数
InBlock.gif
private:
InBlock.gif    
int W;         //记录矩阵的个数

InBlock.gif
    int **m;       //存放最优值,即最小运算量
InBlock.gif
    int **s;       //断开位置
InBlock.gif
    int *p;        //存放
InBlock.gif

InBlock.gif    
bool Input();  //处理输入
InBlock.gif
    bool MatrixChain();//计算最优值算法
InBlock.gif
    void Traceback(int i,int j,int **s);   //输出矩阵加括号的方式
ExpandedBlockEnd.gif
}
;
None.gif
None.gif
#endif

None.gif

           Matrix.cpp代码

None.gif#define N 50
None.gif#include 
<iostream.h>
None.gif#include 
<stdlib.h>
None.gif#include 
"Matrix.h"
None.gif
None.gif
//构造函数,作变量初始化工作,为指针分配内存空间
None.gif
Matrix::Matrix()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
{
InBlock.gif    W
=0
;
InBlock.gif    m 
= new int*
[N];
InBlock.gif    s 
= new int*
[N];
InBlock.gif    
for(int i=0; i<N ; i++
)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif
{
InBlock.gif        m[i] 
= new int
[N];
InBlock.gif        s[i] 
= new int
[N];
ExpandedSubBlockEnd.gif    }

InBlock.gif    p 
= new int[N];
ExpandedBlockEnd.gif}

None.gif
None.gif
//析构函数,释放内存
None.gif
Matrix::~ Matrix()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
{
InBlock.gif    
for(int i=0; i<N ; i++
)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif
{
InBlock.gif        delete []m[i];
InBlock.gif        delete []s[i];
ExpandedSubBlockEnd.gif    }

InBlock.gif    delete []m;
InBlock.gif    delete []s;
InBlock.gif    delete []p;
ExpandedBlockEnd.gif}

None.gif
None.gif
//处理键盘输入
None.gif
bool  Matrix::Input()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
{
InBlock.gif    
int
 w;
InBlock.gif    cout
<<"矩阵个数:"
;
InBlock.gif    cin
>>
w;
InBlock.gif    W 
=
 w;
InBlock.gif    cout
<<"输入矩阵A1维数"<<""
;
InBlock.gif    cin
>>p[0]>>p[1
];
InBlock.gif    
for(int i=2 ; i<=W ; i++
)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif
{
InBlock.gif        
int m = p[i-1
];
InBlock.gif        cout
<<"输入矩阵A"<<i<<"维数:"
;
InBlock.gif        cin
>>p[i-1]>>
p[i];
InBlock.gif        
if(p[i-1!=
 m)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif
{
InBlock.gif            cout
<<endl<<"维数不对,矩阵不可乘!"<<
endl;
InBlock.gif            exit(
1
);
ExpandedSubBlockEnd.gif        }

InBlock.gif        
//cout<<endl;
ExpandedSubBlockEnd.gif
    }

InBlock.gif    
if(p!=NULL)
InBlock.gif        
return true
;
InBlock.gif    
else

InBlock.gif        
return false;
ExpandedBlockEnd.gif}

None.gif
None.gif
//计算最优值算法
None.gif
bool  Matrix::MatrixChain()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
{
InBlock.gif    
if(NULL ==
 p)
InBlock.gif        
return false
;
InBlock.gif    
for(int i=1;i<=W;i++
)
InBlock.gif        m[i][i]
=0
;
InBlock.gif    
for(int r=2;r<=W;r++
)
InBlock.gif        
for(int i=1;i<=W-r+1;i++
)
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif
{
InBlock.gif            
int j=i+r-1
;
InBlock.gif            m[i][j] 
= m[i+1][j] + p[i-1]*p[i]*
p[j];
InBlock.gif            s[i][j] 
=
 i;
InBlock.gif            
for(int k=i+1;k<j;k++
)
ExpandedSubBlockStart.gifContractedSubBlock.gif            
dot.gif
{
InBlock.gif                
int t = m[i][k] + m[k+1][j] + p[i-1]*p[k]*
p[j];
InBlock.gif                
if(t<
m[i][j])
ExpandedSubBlockStart.gifContractedSubBlock.gif                
dot.gif
{
InBlock.gif                    m[i][j] 
=
 t;
InBlock.gif                    s[i][j] 
=
 k;
ExpandedSubBlockEnd.gif                }

ExpandedSubBlockEnd.gif            }

ExpandedSubBlockEnd.gif        }

InBlock.gif    
return true;
ExpandedBlockEnd.gif}

None.gif
None.gif
//输出矩阵结合方式,加括号
None.gif
void Matrix::Traceback(int i,int j,int ** s)
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
{
InBlock.gif    
if(i ==
 j)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif
{
InBlock.gif        cout
<<"A"<<
i;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
else if(i+1 == j)
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif
{
InBlock.gif        cout
<<"(A"<<i<<"A"<<j<<")"
;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
else
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif{
InBlock.gif        cout
<<"("
;
InBlock.gif        Traceback(i,s[i][j],s);
InBlock.gif        Traceback(s[i][j]
+1
,j,s);
InBlock.gif        cout
<<")"
;
ExpandedSubBlockEnd.gif    }

ExpandedBlockEnd.gif}

None.gif
None.gif
bool  Matrix::Run()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
{
InBlock.gif    
if
(Matrix::Input())
ExpandedSubBlockStart.gifContractedSubBlock.gif    
dot.gif
{
InBlock.gif        
if
(Matrix::MatrixChain())
ExpandedSubBlockStart.gifContractedSubBlock.gif        
dot.gif
{
InBlock.gif            Matrix::Traceback(
1
,W,s);
InBlock.gif            cout
<<
endl;
InBlock.gif            
return true
;
ExpandedSubBlockEnd.gif        }

InBlock.gif        
else 
InBlock.gif            
return false
;
ExpandedSubBlockEnd.gif    }

InBlock.gif    
else
InBlock.gif        
return false;
ExpandedBlockEnd.gif}

None.gif

    main.cpp代码

None.gif#include "Matrix.h"
None.gif
None.gif
void  main()
ExpandedBlockStart.gifContractedBlock.gif
dot.gif
{
InBlock.gif    Matrix m;
InBlock.gif    m.Run();
ExpandedBlockEnd.gif}

None.gif

 
                                                    

转载于:https://www.cnblogs.com/ioleon13/archive/2007/05/25/759871.html

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值