动态规划--->矩阵连乘问题

动态规划

矩阵连乘问题

问题描述:

  • 给定n个矩阵{A1,A2,…,An},其中Ai与Ai+1是可乘的,用加括号的方法表示矩阵连乘的次序,不同加括号的方法所对应的计算次序是不同的,求矩阵连乘的最佳计算次序

说明:

  • 1.矩阵A和矩阵B可乘的条件:
    矩阵A的列数=矩阵B的行数
  • 2.矩阵相乘过程中仅涉及加法和乘法,乘法耗时远远大于加法耗时,故采用矩阵连乘所需的乘法次数来代表不同计算次序的计算量
  • 3.设矩阵A是p×q的矩阵,B是q×r的矩阵,乘积的结果C是p×r的矩阵,计算量是p * q * r

最优子结构性质分析:

  • 1.将矩阵连乘的积AiAi+1…Aj简记为A[i][j] (i<=j)
  • 2.考察计算A[1][n]的最优计算次序
    设这个计算次序在矩阵AK和AK+1之间将矩阵链断开(1<=k<=n)
  • 3.计算量: A[i][k]的计算量+A[k+1][n]的计算量+A[1][k]和A[k+1][n]相乘的计算量
  • 4.最优子结构性质: 计算A[1][n]的最优连乘次序所包含的计算矩阵子链A[i][k]和A[k+1][n]的连乘次序也是最优的

建立递归关系:

  • 设计算A[i][j] (i<=j)所需的最少乘法次数为m[i][j]
  • 1.原问题的最优值为m[1][n]
  • 2.当i=j时,A[i][j] = A[i],只有一个矩阵不用相乘,所以m[i][i] = 0
  • 3.当i<j时,m[i][j] =min{ m[i][k] + m[k+1][j] + piqkqj}
    在这里插入图片描述
  • 4.将n个矩阵的行数和列数存储在一位数组P[n](因为q m= p m+1,即第m个矩阵的列数等于第m+1个矩阵的行数 ,因此P中只需要存储n+1个元素,下标是从0 ~ n)
    在这里插入图片描述

算法设计: 自底向上

  • 步骤1:确定合适的数据结构
    1.采用二维数组m来存放各个子问题的最优值
    2.二维数组s来存放各个子问题的最优决策(如果s[i][j] = k,则最优加括号方法为(Ai…Ak)(Ak+1…Aj))
    3.采用一位数组P来存放每个矩阵的的行数
  • 步骤2:初始化
    1.令m[i][i] = 0,s[i][i] = 0(i = 1,2,3,…,n)
  • 步骤3:循环阶段
    步骤3-1:
    按照递归关系系计算两个矩阵AiAi+1 相乘时的最优解并将其存入m[i][i+1]中,同时将最优决策计入s[i][i+1] (i = 1,2,…,n-1)
    步骤3-2:
    按照递归关系式计算3个矩阵AiAi+1Ai+2 相乘时的最优解并将其存入m[i][i+2],同时将最优决策记入s[i][i+2](i = 1,2,…,n-2)
    以此类推,直到
    步骤3-(n-1):
    按照递归关系式计算n个矩阵A1A2…An 相乘时的最优值并将其存入m[1][n],同时将最优决策记入s[1][n]
    至此: m[1][n]即为原问题的最优值
  • 步骤4: 根据二维数组s记录的最优决策信息来构造最优解
    步骤4-1:
    递归构造A1…As[1][n]的最优解,直到只包含一个矩阵结束
    步骤4-2:
    递归构造As[1][n]+1…An的最优解,直到包含一个矩阵结束
    **步骤4-3:**3
    将步骤4-1和4-2递归的结果加括号

例题:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

c++代码:

void MatriChain(){
	for(int i=1; i<=n; i++){
	//初始化,对角线上的计算量和加括号的位置为0,因为只有一个矩阵
		m[i][i] = 0;
		s[i][i] = 0;
	}
	//循环,从计算两个矩阵开始依次往下类推
	for(int r=2; r<=n; r++){
		for(int i=1; i<n-r+1;i++){
			int j = i+r-1;
			//决策为k=i的乘法次数
			m[i][j] = m[i+1][j] + p[i-1]*p[i]*p[j];
			s[i][j] = i;
			//对A~i~...A~j~的所有决策,求最优值,记录最优决策
			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 Traceback(int i,int j,int **s){
	//s[i][j]记录了断开的位置
	if(i==j){
		return;
	}
	//递归打印A[i][s[i][j]]的加括号方式
	Trackback(i,s[i][j],s);
	//递归打印A[s[i][j]+1,[j]]的加括号方式
	Trackback(s[i][j]+1,j,s);
	cout<<"A"<<"["<<i<<":"<<s[i][j]<<"]"<<"乘以"<<"A""["<<(s[i][j]+1)<<":"<<j<<"]"<<endl;
}

算法分析:
在这里插入图片描述

  • 40
    点赞
  • 114
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值