夕拾算法进阶篇:28)矩阵连乘(动态规划DP)

矩阵连乘:
设有矩阵M1,M2,M3,M4,其维数分别是10×20, 20×50, 50×1 和1×100,现要求出这4个矩阵相乘的结果。我们知道,若矩阵A的维数是p×q,矩阵B的维数是q×r,则A与B相乘后所得矩阵AB的维数是p×r。按照矩阵相乘的定义,求出矩阵AB中的一个元素需要做q次乘法(及q-1次加法)。这样,要计算出AB就需要做p×q×r次乘法。为简单起见,且由于加法比同样数量的乘法所用时间要少得多,故这里我们暂不考虑加法的计算量。由于矩阵连乘满足结合律,故计算矩阵连乘的方式可以有多种。
例如,我们可以按M1(M2(M3M4))的方式去计算,也可以按(M1(M2M3))M4的方式去计算,所得结果是相同的。但是值得注意的是,按前一方式计算需要做125,000次乘法,
而按后一方式计算只需要做2,200次乘法。由此可见,矩阵连乘的运算次序对于所需要的计算量(所需乘法次数)有着极大的影响。

如何解决矩阵连乘问题:

设要求出矩阵连乘MiMi+1……Mj-1Mji)所需的最少乘法次数。因共有j-i+1个矩阵,故称这个矩阵连乘的规模是j-i+1

按照做最后一次乘法的位置进行划分,该矩阵连乘一共可分为j-i种情况即有(j-i)种断开方式:Mi(Mi+1Mj)(MiMi+1)(Mi+2Mj),┅,(MiMi+1Mj-1)Mj。其中任一对括号内的矩阵个数(即规模)不超过j-i。若我们已知任一个规模不超过j-i的矩阵连乘所需的最少乘法次数,我们就可以很容易地计算出矩阵连乘MiMi+1Mj-1Mji)所需的最少乘法次数,其方法如下。将上述的j-i种情况表示为通式:(MiMk) (Mk+1Mj)ik)。

记第t个矩阵Mt的列数为rt,并令rt-1为矩阵Mt的行数(相邻两个矩阵,上一个矩阵的列数等于下一个矩阵的行数)。则MiMk连乘所得是ri-1×rk维矩阵,Mk+1Mj连乘所得是rk×rj维矩阵,故这两个矩阵相乘需要做ri-1×rk×rj次乘法。

由于在此之前我们已知任一个规模不超过j-i的矩阵连乘所需的最少乘法次数,故(MiMk)(Mk+1Mj)所需的最少乘法次数已知,将它们分别记之为mi,kmk+1,j。形为(MiMk) (Mk+1Mj)的矩阵连乘所需的最少乘法次数为:mi,k+ mk+1,j + ri-1×rk×rj

对满足ik的共j-i种情况逐一进行比较,我们就可以得到

矩阵连乘MiMi+1Mj-1Mji)所需的最少乘法次数mi,j为:

mi,j=min {   mi,k  +  mk+1,j   +   ri-1×rk×rj   }   ik

于是在初始时我们定义mi,i=0(相当于单个矩阵的情况)

m1,2:即i=1, j=2,就是2个矩阵,无需划分(k=1,因为i<=k

m1,2=min{ m1,1 + m2,2 + ri-1×ri×ri+1}=ri-1×ri×ri+1=r0×r1×r2= 10×20×50=10000

m23:即i=2, j=3,故ri-1×ri×ri+1=r1×r2×r3=20×50×1=1000

m13:即i=1, j=3minik{mik+mk+1,j+ri-1×rk×rj}=min{ (m11+m23+r0×r1×r3)(k=1)(m12+m33+r0×r2×r3)(k=2)}=min{(0+1000+200), (10000+0+500)}= min{1200,10500}=1200

令dp[i][j]是第i个矩阵到第j个矩阵间最小的乘法次数,p[i]表示的是第i个矩阵的列数,其行数用i-1表示。通过上面的分析,可以推导出如下状态转移方程(i<=k


比如给出的矩阵如:10×20, 20×50, 50×1 和1×100,数据格式简化为:10 20 50 1 100,其第一个数(10)表示第一个矩阵的行第二个数(20)表示第一个矩阵的列,其余的都表示当前矩阵的列。

#include 
#include 
#include 
using namespace std;

const int Inf=0x7fffffff;//无穷大 
const int M=105;
int dp[M][M],p[M]; 

int main(){
	int i,j,n,v,k;
	while(cin>>n){
		for(i=0;i>p[i];
		} 
	 	memset(dp,0,sizeof(dp));//初始化边界 
		n-=1; //矩阵的个数为n-1个 首个为第一个矩阵的行,其他皆是列     
	    for(k=2;k<=n;k++){   
	        for(i=1;i+k-1<=n;i++){//左端点枚举位置 
	            j=i+k-1;//     右端点枚举位置 
			 	dp[i][j]=Inf; //选择出矩阵i到矩阵j乘法次数最少的(默认无穷大) 
	            for(v=i;v

参考: http://blog.sina.com.cn/s/blog_64018c250100s123.html

题目来源:http://poj.org/problem?id=1651


你可能感兴趣的:(数据结构和算法)