矩阵连乘
问题描述:
给定n个矩阵{A1,A2,…,An},其中,Ai与Ai+1是可乘的,(i=1,2 ,…,n-1)。用加括号的方法表示矩阵连乘的次序,不同的计算次序计算量(乘法次数)是不同的,找出一种加括号的方法,使得矩阵连乘的次数最小。
比如说:A0(5 10),A1(10 100),A2(100 2)
不同条件下:
(A0 A1)A2 => 5*10*100+5*100*2=6000
A0(A1 A2) => 10*100*2+5*10*2=2100
问题分析
首先矩阵满足结合性,所以可以调换顺序
将问题装换成在一个矩阵上,将各个矩阵的行列数记录在对角线上,然后根据两两相乘得到的结果,将其记录在这两个位置的上方
不断地改变切割点,然后得到相应的值,将其放入矩阵,求出最小的值
相加得到计算量之后,建立递归关系
由此可以算出递归得到的最小值
然后实现打印
代码实现
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
#define MAX 50
int p[MAX+1]; //存储各个矩阵的列数以及第一个矩阵的行数
int m[MAX][MAX]; //m[i][j]存储子问题的最优解
int s[MAX][MAX]; //s[i][j]存储子问题的最佳分割点
int n; //矩阵个数
void matrix(int n,int m[][n],int s[][n],int p[])
{
int i,j,k;
for(i=0;i<n;i++)
m[i][i]=0; //最小子问题仅含有一个矩阵 ,对角线全为0
for(i=2;i<=n;i++) //自底向上
for(j=0;j<=n-i;j++)
{
m[j][j+i-1]=INT_MAX;
for(k=0;k<i-1;k++)
{ //k代表分割点
if(m[j][j+i-1]>m[j][j+k]+m[j+k+1][j+i-1]+p[j]*p[j+k+1]*p[j+i])
{
m[j][j+i-1]=m[j][j+k]+m[j+k+1][j+i-1]+p[j]*p[j+k+1]*p[j+i];
s[j][j+i-1]=k; //记录分割点
}
}
}
}
void printmatrix(int l,int r)//递归打印输出
{
if(l==r)
printf("A%d",l);
else{
printf("(");
printmatrix(l,l+s[l][r]);
printmatrix(l+s[l][r]+1,r);
printf(")");
}
}
int main()
{
int i;
printf("请输入矩阵相乘的矩阵个数");
scanf("%d",&n);
printf("请依次输入矩阵的行和列(如A*B,A=20*30,B=30*40,即输入20 30 40)
") ;
for(i=0;i<=n;i++)
{
scanf("%d",&p[i]);
}
matrix(n,m,s,p);
printf("矩阵连乘最小次数 %d
",m[0][n-1]);
printmatrix(0,n-1);
printf("
");
return 0;
}