算法[动态规划]-矩阵连乘问题

来源:互联网 发布:广东粤数大数据忽悠 编辑:程序博客网 时间:2024/05/17 23:48

动态规划算法的基本要素

(1):最优子结构性质
(2):重叠子问题性质

动态规划法解题思路

(1):找出最优解的性质,并刻画其结构特征
(2):递归的定义最优值
(3):以自底向上的方式计算出最优值
(4):根据计算最优值得到的信息,构造最优解

动态规划与分治的主要区别

(1):分治的自顶向下进行计算的,动态规划是自底向上进行计算的
(2):动态规划法记录了已解决的子问题的解,分治法不记录

矩阵连乘问题的描述

给定N个矩阵A1,A2…An,其中,A(i)和A(i+1)是可乘的,确定计算次序,使得依此次序计算矩阵连乘积需要的数乘次数最少

解决思路

1:将N个矩阵的行列数存入一个大小为N+1的一维数组A中,即:A[0]为第一个矩阵的行数,A[1]为第一个矩阵的列数,又因为第一二个矩阵是可乘的,所以同时又是第二个矩阵的行数,依次存入N个矩阵的行列数
申请一个规格为(N+1) (N+1)的二维数组M用以记录动态规划中的一步步所得的子问题的解,规格为N+1是因为便于在填表时方便易懂。第0行,第0列不填。
再申请一个此规格的二维数组S,用以存储得出的最优子结构的分割点
2:我们再来详细解释一下1中的二维数组M的意义,M[i][j]的意义则代表从第i个矩阵乘到第j个矩阵所乘的最小次数,所以,我们最终所需的结果便是M[1][6]。
由上述亦可得,M表沿对角线左下部分是无用的,对角线上M[i][i]=0,S表亦是。
填完对角线的所有0之后,我们可以考虑填沿对角线向右上方向上的一层,比如M[1][2],M[2][3],M[3][4]…这些我们都可以直接填,因为,它们没有其他解可以比较
沿右上方向,我们再走一层,此时,我们考虑M[1][3],这时,我们知道我们可以(A1 
A2) A3 即当2做cut点时,也可以A1 (A2 A3) 即当1做cut点时 。这时我们将这两种情况所得结果比较,取得最小次数存入。
这两种情况的结果如何得到呢?我们可以有这样的公式(当k为cut点时)`times=M[i][k] + M[k+1][j] + A[i-1] 
A[k] * A[j]`
这样,我们就可以依次填表,最后得到了M[1][N]

C代码实现

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081
#include <stdio.h>#include <stdlib.h>#include <string.h>int Matrix(int *A,int **M,int **S,int n){    int i,l,j,k,q;    for(i = 1;i < n; i++){                      //将对角线置为0        M[i][i] = 0;    }    for(l = 2;l < n; l++){ //第一层循环,从对角线向右上方向推进         for(i = 1;i <= n - l; i++)  //第二层循环,从左上至右下填写         {             j = i + l -1;             M[i][j] = 999999;      //将此值初始为很大的值,便于下面的比较             for(k = i ;k <= j -1; k++){   //第三层循环,列出所有有可能作为cut点的情况并计算结果                    q = M[i][k] + M[k+1][j] + A[i-1] * A[k] * A[j];                   if (q < M[i][j]){                       M[i][j] = q;  //再一次次比较中找出最小次数的情况                       S[i][j] = k;  //并将cut点存入S表作以记录                   }                 }             }         }    return 0;}int PrintMatrix(int **S,int i, int j)    //依据S表打印结果,思想为递归{    if (i == j){        printf("A%d",i);    }    else{        printf("(");        PrintMatrix(S,i,S[i][j]);        PrintMatrix(S,S[i][j] + 1,j);        printf(")");    }    return 0;}int main(){    int A[] = {30,35,15,5,10,20,25};    int i,j;    int n = sizeof(A) / sizeof(int) ;    int **M = (int **)malloc(sizeof(int *) * n);    //申请二维数组    for(i = 0; i < n; i++){        M[i] = (int*)malloc(sizeof(int) * n);    }    int **S = (int **)malloc(sizeof(int *) * n);    for(i = 0; i < n; i++){        S[i] = (int*)malloc(sizeof(int) * n);    }    printf("\n");    Matrix(A,M,S,n);  //调用函数    for ( i = 0; i < n; i++ ){   //打印M表        for( j = 0; j < n; j++ ){            printf("%5d ",M[i][j]);        }        printf("\n");    }    printf("==============================================================\n");    for ( i = 0; i < n; i++ ){   //打印S表        for( j = 0; j < n; j++ ){            printf("%5d",S[i][j]);        }        printf("\n");    }    PrintMatrix(S,1,6);   //显示结果    printf("\n");    return 0;}

实现结果

12345678910111213141516
    0     0     0     0     0     0     0     0     0 15750  7875  9375 11875 15125     0     0     0  2625  4375  7125 10500     0     0     0     0   750  2500  5375     0     0     0     0     0  1000  3500     0     0     0     0     0     0  5000     0     0     0     0     0     0     0 ==============================================================    0    0    0    0    0    0    0    0    0    1    1    3    3    3    0    0    0    2    3    3    3    0    0    0    0    3    3    3    0    0    0    0    0    4    5    0    0    0    0    0    0    5    0    0    0    0    0    0    0((A1(A2A3))((A4A5)A6))

感谢阅读,欢迎指正。

0 0