矩阵连乘问题+adb1bc56-bf1f-44a2-9889-eb90478697f0

一. 题目

输入: n+1个数字 p 0 , p 1 , . . . p n p_0,p_1,...p_n p0,p1,...pn表示矩阵 A 1 , A 2 , . . . , A n A_1,A_2,...,A_n A1,A2,...,An, 其中 A i : p i − 1 ∗ p i A_i:p_{i-1}*p_i Ai:pi1pi ;

输出: 最小的连乘次序, 以及分割方法;

二. 思路分析

将矩阵链 A i A i + 1 . . . A j A_iA_{i+1}...A_j AiAi+1...Aj, 记为 A [ i : j ] A[i:j] A[i:j]

  • 设二维数组 m [ i ] [ j ] m[i][j] m[i][j]为矩阵链 A i A i + 1 . . . A j A_iA_{i+1}...A_j AiAi+1...Aj的最优连乘次数;

  • 设二维数组 s [ i ] [ j ] s[i][j] s[i][j],表示 A i A i + 1 . . . A j A_iA_{i+1}...A_j AiAi+1...Aj的最优分割位置.

建立的递归关系就是

计算A[i:j]所需的最小乘法次数为m(i,j)
在这里插入图片描述

利用表格进行理解: 其中行为i, 列为j

以输入为5,10,3,12,5,50,6为例

在这里插入图片描述

对角线上的元素m[i][i],表示从第i个矩阵乘到第i个矩阵需要的最小乘法计算次数, 这当然是0啦.

从一个长度r=2的矩阵链开始查找所有长度为r的矩阵链的最优乘法次序, r不断增大直到等于原链长度, 即可得到问题的答案.

从表格上看, r=2的部分就是从(1,2)开始的一斜列, 此时k就只有一种情况(k=1); 当r=3时, 所有长度为r的矩阵链对应于表格上(1, 3)开始的一斜列, 对于(1,3)格, 我们需要遍历的是k=1和k=2的情况, 即(1,3)格前面两格的情况, 此规律可以推广到任意一格的计算, 最终的结果在r=6时出现, 即表格上的(1,6)格.

最终最小的乘法次数, 以及分割位置表格如下

在这里插入图片描述

最终的分割形式: ( A 1 A 2 ) ( ( A 3 A 4 ) ( A 5 A 6 ) ) (A_1A_2)((A_3A_4)(A_5A_6)) (A1A2)((A3A4)(A5A6))

三.代码实现

代码如下: (摘录自https://blog.csdn.net/qq_44755403/article/details/105015330)

#include<iostream>
using namespace std;
const int N = 100;
int A[N];//矩阵规模
int m[N][N];//最优解
int s[N][N];//分割位置
void MatrixChain(int n)
{
	int r, i, j, k;
	for (i = 0; i <= n; i++)//初始化对角线
	{
		m[i][i] = 0;
	}
	for (r = 2; r <= n; r++)//r个矩阵连乘
	{
		for (i = 1; i <= n - r + 1; i++)//r个矩阵的r-1个空隙中依次测试最优点
		{//遍历所有长度为r的子矩阵链
			j = i + r - 1;
			m[i][j] = m[i][i]+m[i + 1][j] + A[i - 1] * A[i] * A[j];
			s[i][j] = i;
			for (k = i + 1; k < j; k++)//变换分隔位置,逐一测试
			{
				int t = m[i][k] + m[k + 1][j] + A[i - 1] * A[k] * A[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;
	}
	cout << "(";
	print(i, s[i][j]);
	print(s[i][j] + 1, j);//递归1到s[1][j]
	cout << ")";
}
int main()
{
	int n;//n个矩阵
	cin >> n;
	int i, j;
	for (i = 0; i <= n; i++)
	{
		cin >> A[i];
	}
	MatrixChain(n);
	cout << "最佳添加括号的方式为:";
	print(1, n);
	cout << "\n最小计算量的值为:" << m[1][n] << endl;
	return 0;
}



  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值