矩阵连乘

359 阅读2分钟

这是我参与 8 月更文挑战的第 7 天,活动详情查看: 8月更文挑战

矩阵连乘

1. 思路:

采用备忘录的方法求解。

备忘录方法用表格保存已解决的子问题答案,在下次需要解决此子问题时,只要简单查看该子问题的解答,而不必重新计算。备忘录方法为每一个子问题建立一个记录项,初始化时,该记录项存入一个特殊的值,表示该子问题尚未求解。在求解的过程中,对每个带求的子问题,首先查看其相应的记录项。若记录项中存储的是初始化时存入的特殊值,则表示该问题是第一次遇到,此时计算出该子问题的解,并将其保存在相应的记录项中,以备以后查看。若记录项中存储的已不是初始化时存入的特殊值,则表示该子问题已被计算过,相应的记录项中存储的是该子问题的解答。此时从记录项中取出该子问题的解答即可,而不必重新计算。

#include<iostream>
using namespace std;
//备忘录法求解动态规划

const int L=7;

int lookupChain(int i,int j,int **m,int **s,int *p);
int MemoizeMatrixChain(int n,int **m,int **s,int *p);

void Traceback(int i,int j,int **s);//构造最优解

int main(){
    int p[L]={30,35,15,5,10,20,25};//30x35 35x15 15x5.....

    int **s =new int *[L];
    int **m =new int *[L];
    for(int i=0;i<L;i++){
        s[i]=new int[L];
        m[i]=new int[L];
    }

    cout<<"矩阵的最少计算次数为:"<<MemoizeMatrixChain(L-1,m,s,p)<<endl;
    cout<<"矩阵最优计算次序为:"<<endl;
    Traceback(1,L-1,s);
    system("pause");
    return 0;
}

int MemoizeMatrixChain(int n,int **m,int **s,int *p)
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            m[i][j]=0;//初始化数组
        }
    }
    return lookupChain(1,n,m,s,p);
}

int lookupChain(int i,int j,int **m,int **s,int *p)
{
    if(m[i][j]>0)//若数组M[i][j]不为0,则数组值更新过,直接返回
    {
        return m[i][j];
    }
    if(i==j)//单个矩阵,乘法次数为0
        return 0;

    int u=lookupChain(i,i,m,s,p)+lookupChain(i+1,j,m,s,p)+p[i-1]*p[i]*p[j];
    s[i][j]=i;//s数组用来记录分隔的k值
    for(int k=i+1;k<j;k++)
    {
        int t=lookupChain(i,k,m,s,p)+lookupChain(k+1,j,m,s,p)+p[i-1]*p[k]*p[j];
         if(t<u){//更新最小乘法次数
             u=t;
             s[i][j] = k;
         }
    }
    m[i][j] = u;
    return u;
}

//根据s数组回溯,得到每次括号分割位置
void Traceback(int i,int j,int **s)
{
    if(i==j) return;
    Traceback(i,s[i][j],s);
    Traceback(s[i][j]+1,j,s);
    cout<<"Multiply A"<<i<<","<<s[i][j];
    cout<<"and A"<<(s[i][j]+1)<<","<<j<<endl;
}