动态规划—矩阵乘法排序

矩阵乘法满足结合律,因此可以选择不同的乘法顺序来进行。矩阵乘法进行的次数等于两个子序列各自乘法次数加上两个子序列做一次乘法所需次数。

M left,right=M left,i+M i+1,right+c leftc ic right

M为乘法次数,c[i]等于第i个矩阵的列数。c[0]为第一个矩阵的行数,c[i-1]为第i个矩阵的行数
由于递归在一些情况下会重复计算,导致效率急剧降低,因此需要将递归变为非递归并且用表记录计算结果。
在这里我们需要找出最小乘法次数以及所对应的乘法顺序。
矩阵分别为A=50×10,B=10×40,C=40×30,D=30×5,计算ABCD。

#include <iostream>
#include <vector>
#include <limits>

using namespace std;

//一个简单的矩阵类
template <typename Object>
class Matrix
{
public:
    Matrix(int row,int col):arr(row+1)
    {
        for(auto & x:arr)
        {
            x.resize(col+1);
        }
    }
    vector<Object> & operator [](int row)
    {
        return arr[row];
    }
    const vector<Object> & operator [](int row)const
    {
        return arr[row];
    }

private:
    vector<vector<Object>> arr;
};

//计算矩阵运算的最少乘法次数,存储在m中,最终结果存储在m[1][n]。并记录乘法顺序,记录在lastChange中
//c[0]为第一个矩阵行数,c[i]为第i个矩阵的列数。第i个矩阵的行数等于c[i-1]
void optMatrix(const vector<int> & c,Matrix<int> & m,Matrix<int> & lastChange)
{
    int n=c.size()-1;               //矩阵个数

    for(int left=1;left<=n;++left)
    {
        m[left][left]=0;            //子序列只有一个矩阵,乘法次数为0
    }
    for(int k=1;k<n;++k)            //子序列长度k+1
    {
        for(int left=1;left<=n-k;++left)
        {
            int right=left+k;
            m[left][right]=INT_MAX;

            //遍历子序列的所有可能,找出最小乘法次数
            for(int i=left;i<right;++i)
            {
                int thisCost=m[left][i]+m[i+1][right]
                +c[left-1]*c[i]*c[right];
                if(thisCost<m[left][right])
                {
                    m[left][right]=thisCost;
                    lastChange[left][right]=i;
                }
            }
        }
    }
}

void printOrdering(int left,int right,const Matrix<int> & lastChange)
{
    if(left<right)
    {
        int i=lastChange[left][right];
        cout<<i<<endl;
        printOrdering(left, i, lastChange);
        printOrdering(i+1, right, lastChange);
    }

}

int main()
{
    vector<int> c={50,10,40,30,5};
    int n=c.size()-1;
    Matrix<int> m(n,n);
    Matrix<int> lastChange(n,n);
    optMatrix(c, m, lastChange);
    cout<<m[1][n];

    cout<<endl;

    printOrdering(1, n, lastChange);

}

结果
10500
1
2
3

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值