动态规划_最优矩阵连乘_循环备忘录&递归备忘录

【问题描述】

给定n个矩阵{A1,A2,…,An},其中Ai与Ai+1是可乘的,i=1,2…,n-1。如何确定计算矩阵连乘积的计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少。例如,给定三个连乘矩阵{A1,A2,A3}的维数分别是10100,1005和550,采用(A1A2)A3,乘法次数为101005+10550=7500次,而采用A1(A2A3),乘法次数为100550+10100*50=75000次乘法,显然,最好的次序是(A1A2)A3,乘法次数为7500次。
动态规划_最优矩阵连乘_循环备忘录&递归备忘录_第1张图片
a图 对角线为运算次数,方向为向着右上角运算,即运算到链长为总链长时的最小次数
c图 s(1,6)的值为3,意味着链长从1~6断点为3,s(1,3)断点为1,
再去查找从4~6,s(4,6)=5,断点为5,因此得到结果((A1(A2A3))((A4A5)A6))

动态规划_最优矩阵连乘_循环备忘录&递归备忘录_第2张图片
【源代码】

递归备忘录法:(循环备忘录往下翻⬇)

#include 
using namespace std;

int MatrixChain(int i, int j, int **m, int **s, int *p)
{
    if (m[i][j] > 0)
        return m[i][j];
    if (i == j)
        return 0;
    //m[i][j]表示在上一次的基础上,直接乘剩下矩阵时所得到的次数
    int q = MatrixChain(i, i, m, s, p) + MatrixChain(i + 1, j, m, s, p) + p[i - 1] * p[i] * p[j];
    //s矩阵记录此时的分断位点时i
    s[i][j] = i;
    for (int k = i + 1; k < j; k++)
    {
        //遍历从i+1开始一直到j的分段方法,找到一个最小的乘法次数时的分段方法,保留下来
        int t = MatrixChain(i, k, m, s, p) + MatrixChain(k + 1, j, m, s, p) + p[i - 1] * p[k] * p[j];
        if (t < q)
        {
            q = t;
            //保存断点
            s[i][j] = k;
        }
    }
    //保存数值
    m[i][j] = q;
    return q;
}

void Trace(int i, int j, int **s)
{
    if (i == j)
    {
        cout << "A" << i;
    }
    else
    {
        cout << "(";
        Trace(i, s[i][j], s);
        Trace(s[i][j] + 1, j, s);
        cout << ")";
    }
}

int main()
{
    int size = 7;
    // cout<<"input size:"<
    // cin>>size;
    int p[size] = {30, 35, 15, 5, 10, 20, 25};
    //由于矩阵乘法规则,[]a,b *[]b,c =[]a,c,所以矩阵序列(30,35) (35,15)
    int M[size][size], S[size][size];
    int **m = new int *[size];
    int **s = new int *[size];
    //建立二维向量
    for (int i = 0; i < size; i++)
    {
        m[i] = M[i];
        s[i] = S[i];
    }
    //只有一个矩阵时,不需要乘,次数为0
    for (int i = 1; i <= size; i++)
    {
        for (int j = 1; j <= size; j++)
            m[i][j] = 0;
    }
    MatrixChain(1, size, m, s, p);
    cout << "Min Times:" << m[1][size - 1] << endl;
    //输出二维表
    for (int i = 1; i < size; i++)
    {
        for (int j = i; j < size; j++)
        {
            cout << m[i][j] << "  ";
        }
        cout << endl;
    }
    Trace(1, size - 1, s);
    return 0;
}

循环备忘录法:

#include 
using namespace std;

void MatrixChain(int *p, int n, int **m, int **s)
{
    //只有一个矩阵时,不需要乘,次数为0
    for (int i = 1; i <= n; i++)
        m[i][i] = 0;

    for (int r = 2; r < n; r++)
    {
        //每循环一次,就会对对角线进行一次填充,直到循环到最右上角
        //每次链长+1,所以元素-1
        for (int i = 1; i <= n - r + 1; i++)
        {
            //i为链的起始段,j为链的末端
            int j = i + r - 1;
            //m[i][j]表示在上一次的基础上,直接乘下一个矩阵时所得到的次数
            m[i][j] = m[i + 1][j] + p[i - 1] * p[i] * p[j];
            //s矩阵记录此时的分断位点时i
            s[i][j] = i;

            //比较所有可能分段情况,获得最小值
            for (int k = i + 1; k < j; k++)
            {
                int t = m[i][k] + m[k + 1][j] + p[i - 1] * p[k] * p[j];
                //遍历从i+1开始一直到j的分段方法,找到一个最小的乘法次数时的分段方法,保留下来
                if (t < m[i][j])
                {
                    m[i][j] = t;
                    s[i][j] = k;
                }
            }
        }
    }
}

void Trace(int i, int j, int **s)
{
    if (i == j)
    {
        cout << "A" << i;
    }
    else
    {
        cout << "(";
        Trace(i, s[i][j], s);
        Trace(s[i][j] + 1, j, s);
        cout << ")";
    }
}

int main()
{
    int size = 7;
    // cout<<"input size:"<
    // cin>>size;
    int p[size] = {30, 35, 15, 5, 10, 20, 25};
    //由于矩阵乘法规则,[]a,b *[]b,c =[]a,c,所以矩阵序列(30,35) (35,15)
    int M[size][size], S[size][size];
    int **m = new int *[size];
    int **s = new int *[size];
    //建立二维向量
    for (int i = 0; i < size; i++)
    {
        m[i] = M[i];
        s[i] = S[i];
    }
    MatrixChain(p, size, m, s);
    cout << "Min Times:" << m[1][size - 1] << endl;
    //输出二维表
    for (int i = 1; i < size; i++)
    {
        for (int j = i; j < size; j++)
        {
            cout << m[i][j] << "  ";
        }
        cout << endl;
    }
    Trace(1, size - 1, s);
    return 0;
}

你可能感兴趣的:(动态规划_最优矩阵连乘_循环备忘录&递归备忘录)