Matrxi Chain Order(矩阵链乘法问题)

一、问题介绍:

       给定由n个要相乘的矩阵构成的序列(链)<A1, A2,  ... , An>,要计算乘积:

                                A1, A2...An

       一组矩阵的乘积是加全括号的(fully parenthesized),如果它是单个矩阵,或是两个加全括号的矩阵的乘积外加括号而成。矩阵的乘法满足乘法的结合律,故无论怎样加括号都会产生相同的结果。但加括号的位置会影响标量乘法的个数,从而影响矩阵乘法的计算复杂度。

       这里我们希望找到一种加括号的方式,使得矩阵链的乘法能够进行最少的标量乘法。

二、算法分析:矩阵链乘法问题是动态规划算法里一个比较经典的算法。

      1、最优子结构:

       Ai...j表示AiAi+1...Aj的乘积。对乘积AiAi+1...Aj的任何加全括号形式都将乘积在Ak与Ak+1之间分开,此处k是范围i <= k < j之内的一个整数。所以可以将AiAi+1...Aj分解成Ai..Ak与Ak+1...Aj的两个独立子问题。

      2、 递归定义:

      

      分析上面的递归式,我们发现其时间负责是指数级的,它与检查每一种加全括号乘积的强力算法差不多。但同时我们也可以看到原问题只有相当少的子问题:每一对问题满足1 <= i <= j <= n的i和j对应一个问题,总共O(n2)。一个递归算法在其递归树的不同分支中可能会遇到同一个子问题。子问题重叠这一性质是是否可以采用动态规划的第二个标志(第一个标志是最有子结构)。

      这里我们采用了自底向上的方法。我们定义了矩阵p[i][j]来存储从Ai...Aj矩阵相乘的最小标量乘法数,s[i][j]存储Ai...Aj相乘加括号的位置,具体算法如下:

文件“h1.h"

#ifndef H1_H
#define H1_H

#include<stdio.h>
#include<malloc.h>
#include<stdlib.h>
#include<process.h>
#include<math.h>

#define MAXSIZE 100
#define INFINITY 1000000

struct matrix{
	int row;
	int column;
};

int chainValid(matrix m[], int n);
void matrixChain(matrix m[], int n, int p[][MAXSIZE], int s[][MAXSIZE]);
void Print_Optionmal_Parenthesize(int s[][MAXSIZE], int i, int j);

#endif

文件"MatrixChain.cpp"

#include "h1.h"

int chainValid(matrix m[], int n){

	int i;

	for(i=1; i<n-1; i++){
		if(m[i].column != m[i+1].row){
			return 0;
		}
	}
	return 1;
}

void matrixChain(matrix m[], int n, int p[][MAXSIZE], int s[][MAXSIZE]){

	int l, i, j, k, q;

	for(i=1; i<=n; i++){
		p[i][i] = 0;
	}

	for(l=2; l<=n; l++){
		for(i=1; i<=n-l+1; i++){
			
			j=i+l-1;
			p[i][j] = INFINITY;

			for(k=i; k<=j-1; k++){

				q = p[i][k] + p[k+1][j] + m[i].row * m[k].column * m[j].column;
				if(q < p[i][j]){
					p[i][j] = q;
					s[i][j] = k;
				}
			}
		}
	}
}

void Print_Optionmal_Parenthesize(int s[][MAXSIZE], int i, int j){

	if(i == j){
		printf(" A%d ", i);
	}
	else{
		printf("(");
		Print_Optionmal_Parenthesize(s, i, s[i][j]);
		Print_Optionmal_Parenthesize(s, s[i][j]+1, j);
		printf(")");
	}
}

int main(){

	matrix m[MAXSIZE];
	int p[MAXSIZE][MAXSIZE];
	int s[MAXSIZE][MAXSIZE];

	m[1].row =30;     m[1].column = 35;
	m[2].row = 35;    m[2].column = 15;
	m[3].row = 15;    m[3].column =5;
	m[4].row = 5;     m[4].column = 10;
	m[5].row = 10;	  m[5].column = 20;
	m[6].row = 20;    m[6].column = 25;
	

	if(!chainValid(m, 6)){
		printf("Matrix Chain Invalid!\n");
		return 0;
	}
	matrixChain(m, 6, p, s);

	printf("%d \n", p[1][6]);

	Print_Optionmal_Parenthesize(s, 1, 6);

	return 0;
}

此算法的时间复杂度是O(n 3)。


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值