码迷,mamicode.com
首页 > 其他好文 > 详细

矩阵连乘-动态规划

时间:2020-05-01 12:47:50      阅读:56      评论:0      收藏:0      [点我收藏+]

标签:namespace   规划   c代码   mamicode   png   for   text   递推   结构性   

问题描述

给定n个矩阵\(\{ A_1,A_2,A_3 \dots, A_n \}\),其中\(A_i\)\(A_{i+1}\)是可乘的,\(i=1,2,3,\dots, n-1\)。考察这n个矩阵的连乘积\(A_1A_2\dots A_n\),由于矩阵乘法满足结合律,所以计算矩阵的连乘可以有许多不同的计算次序。这种计算次序可以用加括号的方式来确定。

技术图片

分析最优解结构

dp[i][j]\(A_iA_{i+1}\dots A_j\)的最少乘积次数,并设\(A_iA_{i+1}\dots A_j\)的最优计算次序从矩阵\(A_k\)\(A_{k+1}\)之间断开,\(i\leq k < j\)。那么加括号方式为\(((A_iA_{i+1}\dots A_k)(A_{k+1}\dots A_{j-1}A_{j}))\)
最优总计算量dp[i][j] = dp[i][k] + dp[k+1][j] + A[i:k]与A[k+1:j]乘积次数。其中A[i:k]\(A_iA_{i+1}\dots A_k\)得到的矩阵,A[k+1][j]同理。
得出,矩阵连乘计算次序的最优解包含着其子问题的最优解。这种性质称为最优子结构性质。

解题思路

我们首先默认矩阵的索引从0开始,即\(A_0A_1\dots A_{n-1}\)
创建一个数组dpdp[i][j]用来保存矩阵\(A_i\dots A_j\)的最优乘积次数,在创建一个数组p,用来保存所有矩阵的行列数目。例如上图中的例子,它们的行列数目在p中保存为[50,10,40,30,5]
根据最优解结构的分析,可以得出动态规划的递推公式为:

\[dp[i][j] = \begin{cases} 0 & \text{i = j} \\min_{i\leq k \leq j}(pd[i][k]+pd[k+1][j]+p_ip_{k+1}p_{j+1}) & \text{i $<$ j} \end{cases} \]

为了保证每次计算dp[i][j]时,任意的pd[i][k]pd[k+1][j]都已经得到结果,我们需要首先计算主对角线,然后再依次计算次对角线。

目前我们只是知道了最优计算次数,但是还不知道如何加括号。下面我们再定义一个数组sdp形状相同,用来记录矩阵\(A_i\dots A_j\)之间的最优分割位置k。最后通过递归找到最优加括号位置。

C++代码

#include<iostream>
#include<vector>
using namespace std;

void Traceback(int i,int j,vector<vector<int> >s) // 递归加括号
{ 
	if(i==j) return;
	Traceback(i,s[i][j],s);
    Traceback(s[i][j]+1,j,s);
    cout<<"Multiply A"<<i<<","<<s[i][j];
    cout<<"and A"<<s[i][j]+1<<","<<j<<endl;
}

int main()
{
	int N; 
	cin>>N;
	vector<vector<int> >dp(N, vector<int>(5, 0)); 
	vector<vector<int> >s(N, vector<int>(5, -1)); // 不使用普通数组是为了避免二维数组作为形参时的麻烦
	vector<int>p(N+1);
	
	for(int i=0; i<=N; i++)
		cin>>p[i];
	
	for(int n=1; n<N; n++)
	{
		int i = 0, j = n;
		while(j<N && i<N)
		{
			dp[i][j] = 0x7fffffff;
			int val;
			for(int k=i; k<=j; k++)
			{
				val = dp[i][k]+dp[k+1][j]+p[i]*p[k+1]*p[j+1];
				if(val < dp[i][j])
				{
					dp[i][j] = val; 
					s[i][j] = k;
				}
			}
			i++; j++;
		}
	}
	Traceback(0, N-1, s); // 加括号
	
	cout<<dp[0][N-1];
	return 0;
}

矩阵连乘-动态规划

标签:namespace   规划   c代码   mamicode   png   for   text   递推   结构性   

原文地址:https://www.cnblogs.com/xxmmqg/p/12811385.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!