矩阵连乘之动态规划

矩阵连乘

问题描述:
给定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;
}

原文地址:https://www.cnblogs.com/Indomite/p/14195228.html