矩阵链乘法

1. 问题

在这里插入图片描述

在这里插入图片描述

2. 解析

  • b o t t o m − u p : bottom-up: bottomup: 自底向上。从最底层的小区间开始逐个合并,最后合并到最大的区间。
  • d i v i d e : divide: divide: 区间的分割。根据分割点k,我们可以分割为两个区间,例如 [ i , j ] [i,j] [i,j] 可以分割为 [ i , k ] [i,k] [i,k] [ k + 1 , j ] [k+1,j] [k+1,j] 两个区间。
  • t r a n s f e r : transfer: transfer: 状态的转移,或可以说是区间的合并。由于 [ i , k ] [i,k] [i,k] [ k + 1 , j ] [k+1,j] [k+1,j] 的区间长度肯定比 [ i , j ] [i,j] [i,j] 要小, 由于我们升序枚举区间长度,所以当前这两个区间的状态值已经是最优的,又由于大区间由子区间合并而成,所以我们可以取其中某几个子区间合并的最优的状态值作为当前 [ i , j ] [i,j] [i,j] 的最优状态值。
  • 例如: P = < 30 , 35 , 15 , 5 , 10 , 20 , 25 > , n = 6 P=<30,35,15,5,10,20,25>, n=6 P=<30,35,15,5,10,20,25>,n=6
  • A1:30*35, A2:35*15, A3:15*5, A4:5*10, A5:10*20, A6:20*25
  • m [ i ] [ j ] m[i][j] m[i][j] 代表区间 [ i , j ] [i,j] [i,j] 最优状态值, s [ i ] [ j ] s[i][j] s[i][j] 代表区间 [ i , j ] [i,j] [i,j] 的分割点
  • (1)
    r=1
    m[1,1]=0;
    m[2,2]=0;
    m[3,3]=0;
    m[4,4]=0;
    m[5,5]=0;
    m[6,6]=0;
  • (2)
    r=2,i=1,2,3,4,5; j=2,3,4,5,6
    m[1,2]=30*35*15=15750;
    m[2,3]=35*15*5=2625;
    m[3,4]=15*5*10=750;
    m[4,5]=5*10*20=1000;
    m[5,6]=10*20*25=5000
  • (3)
    r=3,i=1,2,3,4; j=3,4,5,6
    m[1,3]=min{m[1,2]+m[3,3]+(A1A2)A3,m[1,1]+m[2,3]+A1(A2A3)};s[1,3]=1
    m[2,4]=min{m[2,3]+m[4,4]+(A2A3)A4,m[2,2]+m[3,4]+A2(A3A4)};s[2,4]=3
    m[3,5]=min{m[3,4]+m[5,5]+(A3A4)A5,m[3,3]+m[4,5]+A3(A4A5)};s[3,5]=3
    m[4,6]=min{m[4,5]+m[5,6]+(A4A5)A6,m[4,4]+m[5,6]+A4(A5A6)};s[4,6]=5
  • (4)
    r=4, i=1,2,3; j=4,5,6
    m[1,4]=min{m[1,1]+m[2,4]+A1(A2A3A4),m[1,2]+m[3,4]+(A1A2)(A3A4),m[1,3]+m[4,4]+(A1A2A3)A4};s[1,4]=3
    m[2,5]=min{m[2,2]+m[3,5]+A2(A3A4A5),m[2,3]+m[4,5]+(A2A3)(A4A5),m[2,4]+m[5,5]+(A2A3A4)A5};s[2,5]=3
    m[3,6]=min{m[3,3]+m[4,6]+(A3A4A5)A6,m[3,4]+m[5,6]+(A3A4)(A5A6),m[3,5]+m[6,6]+(A3A4A5)A6};s[3,6]=3
  • (5)
    r=5,i=1,2; j=5,6
    m[1,5]=min{m[1,1]+m[2,5]+A1(A2A3A4A5),m[1,2]+m[3,5]+(A1A2)(A3A4A5),m[1,3]+m[4,5]+(A1A2A3)(A4A5);m[1,4]+m[5,5]+(A1A2A3A4)A5};s[1,5]=3
    m[2,6]=min{m[2,2]+m[3,6]+A2(A3A4A5A6),m[2,3]+m[4,6]+(A2A3)(A4A5A6),m[2,4]+m[5,6]+(A2A3A4)(A5A6);m[2,5]+m[6,6]+(A2A3A4A5)A6};s[2,6]=3
  • (6)
    r=6,i=1; j=6
    m[1,6]=min{m[1,1]+m[2,6]+A1(A2A3A4A5A6),m[1,2]+m[3,6]+(A1A2)(A3A4A5A6),m[1,3]+m[4,6]+(A1A2A3)(A4A5A6);m[1,4]+m[5,6]+(A1A2A3A4)(A5A6);m[1,5]+m[6,6]+(A1A2A3A4A5)A6};s[1,6]=3
  • s[1,6]=3 (A1A2A3)(A4A5A6), s[1,3]=1,s[1,6]=5 (A1(A2A3))((A4A5)A6)
  • 结果:(A1(A2A3))((A4A5)A6)

3. 设计

矩阵链乘算法

#include<bits/stdc++.h>
using namespace std;
const int inf = 0x3f3f3f3f;
const int N = 1e3+10;

int n,m,x;
vector<int>p;
int dp[N][N],sep[N][N];

//矩阵链乘法
void matrixChain() {
	//枚举区间长度
	for (int d=1;d<=n;d++) {
		//枚举区间左端点
		for (int i=1;i<=n-d;i++) {
			//区间右端点
			int j=i+d;
			//枚举区间分割点
			for (int k=i;k<j;k++) {
				//p[i-1]代表Ai的行数,p[k]代表Ak的的列数,p[j]代表Aj的列数
				int temp = dp[i][k]+dp[k+1][j]+p[i-1]*p[k]*p[j];
				if (dp[i][j] > temp) {
					dp[i][j] = temp;
					sep[i][j] = k;
				}
			}
		}
	}
	cout<<dp[1][n]<<endl;
}

//输出矩阵链乘法的方案
void printChain(int l,int r) {
	if (l==r) {
		cout<<"A"<<l;
		return;
	}
	cout<<"(";
	printChain(l,sep[l][r]);
	printChain(sep[l][r]+1,r);
	cout<<")";
}

void run() {
	memset(dp,inf,sizeof dp);
	cin>>n;
	for (int i=0;i<=n;i++) {
		cin>>m;
		p.push_back(m);
		dp[i][i] = 0;
	}
	matrixChain();
	printChain(1,n);
}

int main() {
	run();
	return 0;
}

/*
6
30 35 15 5 10 20 25
*/

4. 分析

  • 循环嵌套为三层,每层循环变量大小为 n n n ,所以总时间复杂度为 O ( n 3 ) O(n^3) O(n3)

5. 源码

https://github.com/a894985555/Algorithm/tree/main/%E7%9F%A9%E9%98%B5%E9%93%BE%E4%B9%98%E6%B3%95

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值