一. 问题描述
给定n个矩阵{A1,A2,A3,……An},其中Ai和Ai+1是可乘的,要求确定矩阵连乘的计算次序,使得矩阵连乘需要的数乘次数最少。
二.解法
先看两个矩阵相乘: A 1 A_1 A1是 p 0 ∗ p 1 p_0*p_1 p0∗p1的矩阵, A 2 A_2 A2是 p 1 ∗ p 2 p_1*p_2 p1∗p2的矩阵,则 A 1 ∗ A 2 A_1*A_2 A1∗A2是 p 0 ∗ p 2 p_0*p_2 p0∗p2的矩阵,新矩阵中每一个元素是由 p 1 p_1 p1对数的乘积求和的得到的,即两个矩阵相乘需要的数乘次数为 p 0 ∗ p 2 ∗ p 1 p_0*p_2*p_1 p0∗p2∗p1。
为了方便起见,给出如下定义:
1) A i = p i − 1 ∗ p i A_i=p_{i-1}*p_i Ai=pi−1∗pi,即 A i − 1 A_{i-1} Ai−1是一个 p i − 1 p_{i-1} pi−1行 p i p_i pi列的矩阵。
2) A [ i : j ] A[i:j] A[i:j]——矩阵连乘积 A i A i + 1 … A j A_{i}A_{i+1}…A_{j} AiAi+1…Aj( A [ i : j ] A[i:j] A[i:j]是一个 p i − 1 ∗ p j p_{i-1}*p_j pi−1∗pj的矩阵)。
3 )用二维数组 m [ i ] [ j ] m[i][j] m[i][j]记录 A [ i : j ] A[i:j] A[i:j]的最优解。
动态规划的思想就是保留最优子结构的解,然后由子结构的最优解逐步得到原来问题的解。 m [ i ] [ j ] m[i][j] m[i][j]就相当于一个备忘录,它记录着子结构的最优解。
m [ i ] [ j ] m[i][j] m[i][j]的递推公式如下:
三.C语言代码
#include <stdio.h>
#define MAX 100
int m[MAX][MAX];
int getMin(int Min[],int len){ //返回Min{}中的最小值
int i;
int min=Min[0];
for(i=1;i<len;i++){
if(Min[i]<min)
min=Min[i];
}
return min;
}
int MatriChain(int n,int p[]){ //n个矩阵连乘,每个矩阵的规模用数组p传递
int Min[n]; //存放min{}中的值以便于比较
int index=0; //表示Min数组的下标
int i;
for(i=1;i<=n;i++)
m[i][i]=0; //m从(1,1)位置开始存储,方便理解
int j; //j为连乘矩阵的个数,控制问题规模
int k; //k表示连乘矩阵中最左矩阵的序号(如A[2,4]=A2*A3*A4 ,j=3,k=2)
int mid; //用于划分A[i:j]
for(j=2;j<=n;j++){
for(k=1;k<=n-j+1;k++){
for(mid=k;mid<k+j-1;mid++){
Min[index++]=m[k][mid]+m[mid+1][k+j-1]+p[k-1]*p[mid]*p[k+j-1];
}
m[k][k+j-1]=getMin(Min,j-1);
index=0;
}
}
return m[1][n];
}
int main(){
int n=6; //矩阵个数
int p[7]={30,35,15,5,10,20,25}; //矩阵规模信息,根据矩阵连乘的要求,需要用n+1个数保存n个矩阵的规模信息
int matri_num=MatriChain(n,p);
printf("一共进行了%d次数乘",matri_num);
return 0;
}