【动态规划篇(1)---矩阵连乘问题的最优解】

目录

【递归解】

 运行结果

【非递归解】

 运行结果:


问题: 见课本《算法分析与设计》4.1---4.2;

分析:已知所给的矩阵可以按顺序从前往后做乘法运算,所以已经满足乘法运算的条件:前列等于后行。

m*n矩阵与n*p矩阵运算时,进行乘法运算m*n*p次。

要求最优解,即遍历找出主序列中第一个括号的位置,然后分别再遍历剩下的两个子序列,依此类推,确定本序列中加括号的所有位置,即得最优解。

Dg(i,k)+Dg(k+1,j)+p[i-1]*p[k]*p[j];表示在k之后加一个括号,计算两大块各自的的乘法运算次数再加上两大块矩阵做乘法运算的次数,即为当前矩阵序列的连乘问题最优解

说明:m[i][j]记录从i到j的序列的乘法问题最优解,s[i][j]记录从i到j的序列中加括号的位置。

【递归解】

#include <bits/stdc++.h>
using namespace std;
int m[40][40],s[40][40],p[40];
int Dg(int i,int j)//递归的备忘录算法
{
    //备忘录算法只需要比正常的递归算法多这一句话,但是不加这句话会更快(神奇)
    //if(m[i][j]>0) return m[i][j];

    if(i==j) return 0;
    int u=Dg(i,i)+Dg(i+1,j)+p[i-1]*p[i]*p[j];
    s[i][j]=i;
    m[i][j]=u;
    for(int k=i+1;k<j;k++)
    {
        int t=Dg(i,k)+Dg(k+1,j)+p[i-1]*p[k]*p[j];
        if(t<u){m[i][j]=t;s[i][j]=k;}
    }
    return m[i][j];
}
//50 10 40 30 5 20 15
void HuaFen(int i,int j)
{
    if(i==j) cout<<"A"<<i;
    else {cout<<"(";
    HuaFen(i,s[i][j]);
    HuaFen(s[i][j]+1,j);
    cout<<")";
    }
}
int main()
{
    cout<<"请输入p数组中的数";
    //题目中假设所有矩阵可以顺序连乘。p数组存储矩阵的阶数,eg:第一个矩阵m*n,则p[1-1]=m,p[1]=n;
    for(int i=0;i<7;i++)
        cin>>p[i];
    cout<<"矩阵连乘的最优解是"<<Dg(1,6);
    cout<<endl<<"加括号的方式为:";
    HuaFen(1,6);
}

 运行结果

 

【非递归解】

求解m[i][j]、s[i][j]按照对角线的方式从主对角线开始向右上角进行运算,

代码: 

#include <bits/stdc++.h>
using namespace std;
const int N=100;
int p[N]={50,10,40,30,5,20,15};
int s[N][N];
int m[N][N];

void Mincheng(int n)
{
    for(int i=1;i<=n;i++) m[i][i]=0;//矩阵自身不做乘法运算,所以初始化为0
    for(int r=2;r<=n;r++)//指定进行矩阵划分的区间大小为r
    {
        for(int i=1;i<=n-r+1;i++)//指定区间开始的下标
        {
            int j=i+r-1;//区间末尾的下标
            //初始化:先算从第一个元素开始划分的乘法运算次数
            m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j];
            s[i][j]=i;
            //计算从k处开始划分的乘法运算次数
            for(int k=i+1;k<=j;k++)
            {
                int t=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
                if(t<m[i][j])
                {
                    m[i][j]=t;s[i][j]=k;
                }
            }
        }
    }
}
void print(int i,int j)
{
    if(i==j) {cout<<"A"<<i;return ;}
    else
    {
        cout<<"(";
        print(i,s[i][j]);
        print(s[i][j]+1,j);
        cout<<")";
    }
}
int main()
{
    Mincheng(6);
    print(1,6);
    cout<<"\n连乘积的最小乘法运算次数为:"<<m[1][6];

}

 运行结果:

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

迎风809

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值